@@ -183,15 +183,6 @@ static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) {
183183 return false ;
184184}
185185
186- void static
187- removeInstructions (ArrayRef<SILInstruction*> UsersToRemove) {
188- for (auto *I : UsersToRemove) {
189- I->replaceAllUsesOfAllResultsWithUndef ();
190- // Now we know that I should not have any uses... erase it from its parent.
191- I->eraseFromParent ();
192- }
193- }
194-
195186// ===----------------------------------------------------------------------===//
196187// Use Graph Analysis
197188// ===----------------------------------------------------------------------===//
@@ -682,93 +673,6 @@ static void insertReleases(ArrayRef<StoreInst*> Stores,
682673 }
683674}
684675
685- // Attempt to remove the array allocated at NewAddrValue and release its
686- // refcounted elements.
687- //
688- // This is tightly coupled with the implementation of array.uninitialized.
689- // The call to allocate an uninitialized array returns two values:
690- // (Array<E> ArrayBase, UnsafeMutable<E> ArrayElementStorage)
691- //
692- // TODO: This relies on the lowest level array.uninitialized not being
693- // inlined. To do better we could either run this pass before semantic inlining,
694- // or we could also handle calls to array.init.
695- static bool removeAndReleaseArray (SingleValueInstruction *NewArrayValue,
696- DeadEndBlocks &DEBlocks) {
697- TupleExtractInst *ArrayDef = nullptr ;
698- TupleExtractInst *StorageAddress = nullptr ;
699- for (auto *Op : NewArrayValue->getUses ()) {
700- auto *TupleElt = dyn_cast<TupleExtractInst>(Op->getUser ());
701- if (!TupleElt)
702- return false ;
703- if (TupleElt->getFieldIndex () == 0 && !ArrayDef) {
704- ArrayDef = TupleElt;
705- } else if (TupleElt->getFieldIndex () == 1 && !StorageAddress) {
706- StorageAddress = TupleElt;
707- } else {
708- return false ;
709- }
710- }
711- if (!ArrayDef)
712- return false ; // No Array object to delete.
713-
714- assert (!ArrayDef->getType ().isTrivial (*ArrayDef->getFunction ()) &&
715- " Array initialization should produce the proper tuple type." );
716-
717- // Analyze the array object uses.
718- DeadObjectAnalysis DeadArray (ArrayDef);
719- if (!DeadArray.analyze ())
720- return false ;
721-
722- // Require all stores to be into the array storage not the array object,
723- // otherwise bail.
724- bool HasStores = false ;
725- DeadArray.visitStoreLocations ([&](ArrayRef<StoreInst*>){ HasStores = true ; });
726- if (HasStores)
727- return false ;
728-
729- // Remove references to empty arrays.
730- if (!StorageAddress) {
731- removeInstructions (DeadArray.getAllUsers ());
732- return true ;
733- }
734- assert (StorageAddress->getType ().isTrivial (*ArrayDef->getFunction ()) &&
735- " Array initialization should produce the proper tuple type." );
736-
737- // Analyze the array storage uses.
738- DeadObjectAnalysis DeadStorage (StorageAddress);
739- if (!DeadStorage.analyze ())
740- return false ;
741-
742- // Find array object lifetime.
743- ValueLifetimeAnalysis VLA (NewArrayValue, DeadArray.getAllUsers ());
744-
745- // Check that all storage users are in the Array's live blocks.
746- for (auto *User : DeadStorage.getAllUsers ()) {
747- if (!VLA.isWithinLifetime (User))
748- return false ;
749- }
750- // For each store location, insert releases.
751- SILSSAUpdater SSAUp;
752- ValueLifetimeAnalysis::Frontier ArrayFrontier;
753- if (!VLA.computeFrontier (ArrayFrontier,
754- ValueLifetimeAnalysis::UsersMustPostDomDef,
755- &DEBlocks)) {
756- // In theory the allocated object must be released on all paths in which
757- // some object initialization occurs. If not (for some reason) we bail.
758- return false ;
759- }
760-
761- DeadStorage.visitStoreLocations ([&] (ArrayRef<StoreInst*> Stores) {
762- insertReleases (Stores, ArrayFrontier, SSAUp);
763- });
764-
765- // Delete all uses of the dead array and its storage address.
766- removeInstructions (DeadArray.getAllUsers ());
767- removeInstructions (DeadStorage.getAllUsers ());
768-
769- return true ;
770- }
771-
772676// ===----------------------------------------------------------------------===//
773677// Function Processing
774678// ===----------------------------------------------------------------------===//
@@ -785,12 +689,21 @@ namespace {
785689class DeadObjectElimination : public SILFunctionTransform {
786690 llvm::DenseMap<SILType, bool > DestructorAnalysisCache;
787691
692+ InstructionDeleter deleter;
693+
694+ void removeInstructions (ArrayRef<SILInstruction*> toRemove);
695+
788696 bool processAllocRef (AllocRefInst *ARI);
789697 bool processAllocStack (AllocStackInst *ASI);
790698 bool processKeyPath (KeyPathInst *KPI);
791699 bool processAllocBox (AllocBoxInst *ABI){ return false ;}
792700 bool processAllocApply (ApplyInst *AI, DeadEndBlocks &DEBlocks);
793701
702+ bool getDeadInstsAfterInitializerRemoved (
703+ ApplyInst *AI, llvm::SmallVectorImpl<SILInstruction *> &ToDestroy);
704+ bool removeAndReleaseArray (
705+ SingleValueInstruction *NewArrayValue, DeadEndBlocks &DEBlocks);
706+
794707 bool processFunction (SILFunction &Fn) {
795708 DeadEndBlocks DEBlocks (&Fn);
796709 DestructorAnalysisCache.clear ();
@@ -799,19 +712,7 @@ class DeadObjectElimination : public SILFunctionTransform {
799712
800713 for (auto &BB : Fn) {
801714
802- llvm::SmallVector<SILInstruction*, 64 > instsToProcess;
803- for (SILInstruction &inst : BB) {
804- if (isa<AllocationInst>(&inst) ||
805- isAllocatingApply (&inst) ||
806- isa<KeyPathInst>(&inst)) {
807- instsToProcess.push_back (&inst);
808- }
809- }
810-
811- for (SILInstruction *inst : instsToProcess) {
812- if (inst->isDeleted ())
813- continue ;
814-
715+ for (SILInstruction *inst : deleter.updatingRange (&BB)) {
815716 if (auto *A = dyn_cast<AllocRefInst>(inst))
816717 Changed |= processAllocRef (A);
817718 else if (auto *A = dyn_cast<AllocStackInst>(inst))
@@ -823,6 +724,7 @@ class DeadObjectElimination : public SILFunctionTransform {
823724 else if (auto *A = dyn_cast<ApplyInst>(inst))
824725 Changed |= processAllocApply (A, DEBlocks);
825726 }
727+ deleter.cleanupDeadInstructions ();
826728 }
827729 return Changed;
828730 }
@@ -840,6 +742,15 @@ class DeadObjectElimination : public SILFunctionTransform {
840742};
841743} // end anonymous namespace
842744
745+ void
746+ DeadObjectElimination::removeInstructions (ArrayRef<SILInstruction*> toRemove) {
747+ for (auto *I : toRemove) {
748+ I->replaceAllUsesOfAllResultsWithUndef ();
749+ // Now we know that I should not have any uses... erase it from its parent.
750+ deleter.forceDelete (I);
751+ }
752+ }
753+
843754bool DeadObjectElimination::processAllocRef (AllocRefInst *ARI) {
844755 // Ok, we have an alloc_ref. Check the cache to see if we have already
845756 // computed the destructor behavior for its SILType.
@@ -932,7 +843,7 @@ bool DeadObjectElimination::processKeyPath(KeyPathInst *KPI) {
932843// / If AI is the version of an initializer where we pass in either an apply or
933844// / an alloc_ref to initialize in place, validate that we are able to continue
934845// / optimizing and return To
935- static bool getDeadInstsAfterInitializerRemoved (
846+ bool DeadObjectElimination:: getDeadInstsAfterInitializerRemoved (
936847 ApplyInst *AI, llvm::SmallVectorImpl<SILInstruction *> &ToDestroy) {
937848 assert (ToDestroy.empty () && " We assume that ToDestroy is empty, so on "
938849 " failure we can clear without worrying about the "
@@ -973,6 +884,93 @@ static bool getDeadInstsAfterInitializerRemoved(
973884 return true ;
974885}
975886
887+ // Attempt to remove the array allocated at NewAddrValue and release its
888+ // refcounted elements.
889+ //
890+ // This is tightly coupled with the implementation of array.uninitialized.
891+ // The call to allocate an uninitialized array returns two values:
892+ // (Array<E> ArrayBase, UnsafeMutable<E> ArrayElementStorage)
893+ //
894+ // TODO: This relies on the lowest level array.uninitialized not being
895+ // inlined. To do better we could either run this pass before semantic inlining,
896+ // or we could also handle calls to array.init.
897+ bool DeadObjectElimination::removeAndReleaseArray (
898+ SingleValueInstruction *NewArrayValue, DeadEndBlocks &DEBlocks) {
899+ TupleExtractInst *ArrayDef = nullptr ;
900+ TupleExtractInst *StorageAddress = nullptr ;
901+ for (auto *Op : NewArrayValue->getUses ()) {
902+ auto *TupleElt = dyn_cast<TupleExtractInst>(Op->getUser ());
903+ if (!TupleElt)
904+ return false ;
905+ if (TupleElt->getFieldIndex () == 0 && !ArrayDef) {
906+ ArrayDef = TupleElt;
907+ } else if (TupleElt->getFieldIndex () == 1 && !StorageAddress) {
908+ StorageAddress = TupleElt;
909+ } else {
910+ return false ;
911+ }
912+ }
913+ if (!ArrayDef)
914+ return false ; // No Array object to delete.
915+
916+ assert (!ArrayDef->getType ().isTrivial (*ArrayDef->getFunction ()) &&
917+ " Array initialization should produce the proper tuple type." );
918+
919+ // Analyze the array object uses.
920+ DeadObjectAnalysis DeadArray (ArrayDef);
921+ if (!DeadArray.analyze ())
922+ return false ;
923+
924+ // Require all stores to be into the array storage not the array object,
925+ // otherwise bail.
926+ bool HasStores = false ;
927+ DeadArray.visitStoreLocations ([&](ArrayRef<StoreInst*>){ HasStores = true ; });
928+ if (HasStores)
929+ return false ;
930+
931+ // Remove references to empty arrays.
932+ if (!StorageAddress) {
933+ removeInstructions (DeadArray.getAllUsers ());
934+ return true ;
935+ }
936+ assert (StorageAddress->getType ().isTrivial (*ArrayDef->getFunction ()) &&
937+ " Array initialization should produce the proper tuple type." );
938+
939+ // Analyze the array storage uses.
940+ DeadObjectAnalysis DeadStorage (StorageAddress);
941+ if (!DeadStorage.analyze ())
942+ return false ;
943+
944+ // Find array object lifetime.
945+ ValueLifetimeAnalysis VLA (NewArrayValue, DeadArray.getAllUsers ());
946+
947+ // Check that all storage users are in the Array's live blocks.
948+ for (auto *User : DeadStorage.getAllUsers ()) {
949+ if (!VLA.isWithinLifetime (User))
950+ return false ;
951+ }
952+ // For each store location, insert releases.
953+ SILSSAUpdater SSAUp;
954+ ValueLifetimeAnalysis::Frontier ArrayFrontier;
955+ if (!VLA.computeFrontier (ArrayFrontier,
956+ ValueLifetimeAnalysis::UsersMustPostDomDef,
957+ &DEBlocks)) {
958+ // In theory the allocated object must be released on all paths in which
959+ // some object initialization occurs. If not (for some reason) we bail.
960+ return false ;
961+ }
962+
963+ DeadStorage.visitStoreLocations ([&] (ArrayRef<StoreInst*> Stores) {
964+ insertReleases (Stores, ArrayFrontier, SSAUp);
965+ });
966+
967+ // Delete all uses of the dead array and its storage address.
968+ removeInstructions (DeadArray.getAllUsers ());
969+ removeInstructions (DeadStorage.getAllUsers ());
970+
971+ return true ;
972+ }
973+
976974bool DeadObjectElimination::processAllocApply (ApplyInst *AI,
977975 DeadEndBlocks &DEBlocks) {
978976 // Currently only handle array.uninitialized
@@ -989,12 +987,10 @@ bool DeadObjectElimination::processAllocApply(ApplyInst *AI,
989987
990988 LLVM_DEBUG (llvm::dbgs () << " Success! Eliminating apply allocate(...).\n " );
991989
992- InstructionDeleter deleter;
993990 deleter.forceDeleteWithUsers (AI);
994991 for (auto *toDelete : instsDeadAfterInitializerRemoved) {
995992 deleter.trackIfDead (toDelete);
996993 }
997- deleter.cleanupDeadInstructions ();
998994
999995 ++DeadAllocApplyEliminated;
1000996 return true ;
0 commit comments