mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
DeadObjectElimination: handle objects for which the destructor is de-virtualized and inlined
Also: add an additional DeadObjectElimination pass in the low level pipeline because redundant load elimination (which runs before) can turn an object into a dead object.
This commit is contained in:
@@ -193,11 +193,16 @@ removeInstructions(ArrayRef<SILInstruction*> UsersToRemove) {
|
||||
|
||||
/// Returns false if Inst is an instruction that would require us to keep the
|
||||
/// alloc_ref alive.
|
||||
static bool canZapInstruction(SILInstruction *Inst) {
|
||||
static bool canZapInstruction(SILInstruction *Inst, bool acceptRefCountInsts) {
|
||||
if (isa<SetDeallocatingInst>(Inst) || isa<FixLifetimeInst>(Inst))
|
||||
return true;
|
||||
|
||||
// It is ok to eliminate various retains/releases. We are either removing
|
||||
// everything or nothing.
|
||||
if (isa<RefCountingInst>(Inst) || isa<StrongPinInst>(Inst))
|
||||
return true;
|
||||
if (isa<RefCountingInst>(Inst) || isa<StrongPinInst>(Inst) ||
|
||||
// dealloc_partial_ref invokes releases implicitly
|
||||
isa<DeallocPartialRefInst>(Inst))
|
||||
return acceptRefCountInsts;
|
||||
|
||||
// If we see a store here, we have already checked that we are storing into
|
||||
// the pointer before we added it to the worklist, so we can skip it.
|
||||
@@ -227,7 +232,8 @@ static bool canZapInstruction(SILInstruction *Inst) {
|
||||
/// Analyze the use graph of AllocRef for any uses that would prevent us from
|
||||
/// zapping it completely.
|
||||
static bool
|
||||
hasUnremovableUsers(SILInstruction *AllocRef, UserList &Users) {
|
||||
hasUnremovableUsers(SILInstruction *AllocRef, UserList &Users,
|
||||
bool acceptRefCountInsts) {
|
||||
SmallVector<SILInstruction *, 16> Worklist;
|
||||
Worklist.push_back(AllocRef);
|
||||
|
||||
@@ -246,7 +252,7 @@ hasUnremovableUsers(SILInstruction *AllocRef, UserList &Users) {
|
||||
}
|
||||
|
||||
// If we can't zap this instruction... bail...
|
||||
if (!canZapInstruction(I)) {
|
||||
if (!canZapInstruction(I, acceptRefCountInsts)) {
|
||||
DEBUG(llvm::dbgs() << " Found instruction we can't zap...\n");
|
||||
return true;
|
||||
}
|
||||
@@ -695,15 +701,11 @@ bool DeadObjectElimination::processAllocRef(AllocRefInst *ARI) {
|
||||
DestructorAnalysisCache[Type] = HasSideEffects;
|
||||
}
|
||||
|
||||
if (HasSideEffects) {
|
||||
DEBUG(llvm::dbgs() << " Destructor had side effects. \n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Our destructor has no side effects, so if we can prove that no loads
|
||||
// escape, then we can completely remove the use graph of this alloc_ref.
|
||||
UserList UsersToRemove;
|
||||
if (hasUnremovableUsers(ARI, UsersToRemove)) {
|
||||
if (hasUnremovableUsers(ARI, UsersToRemove,
|
||||
/*acceptRefCountInsts=*/ !HasSideEffects)) {
|
||||
DEBUG(llvm::dbgs() << " Found a use that cannot be zapped...\n");
|
||||
return false;
|
||||
}
|
||||
@@ -723,7 +725,7 @@ bool DeadObjectElimination::processAllocStack(AllocStackInst *ASI) {
|
||||
return false;
|
||||
|
||||
UserList UsersToRemove;
|
||||
if (hasUnremovableUsers(ASI, UsersToRemove)) {
|
||||
if (hasUnremovableUsers(ASI, UsersToRemove, /*acceptRefCountInsts=*/ true)) {
|
||||
DEBUG(llvm::dbgs() << " Found a use that cannot be zapped...\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user