@@ -183,15 +183,6 @@ static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) {
183
183
return false ;
184
184
}
185
185
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
-
195
186
// ===----------------------------------------------------------------------===//
196
187
// Use Graph Analysis
197
188
// ===----------------------------------------------------------------------===//
@@ -682,93 +673,6 @@ static void insertReleases(ArrayRef<StoreInst*> Stores,
682
673
}
683
674
}
684
675
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
-
772
676
// ===----------------------------------------------------------------------===//
773
677
// Function Processing
774
678
// ===----------------------------------------------------------------------===//
@@ -785,12 +689,21 @@ namespace {
785
689
class DeadObjectElimination : public SILFunctionTransform {
786
690
llvm::DenseMap<SILType, bool > DestructorAnalysisCache;
787
691
692
+ InstructionDeleter deleter;
693
+
694
+ void removeInstructions (ArrayRef<SILInstruction*> toRemove);
695
+
788
696
bool processAllocRef (AllocRefInst *ARI);
789
697
bool processAllocStack (AllocStackInst *ASI);
790
698
bool processKeyPath (KeyPathInst *KPI);
791
699
bool processAllocBox (AllocBoxInst *ABI){ return false ;}
792
700
bool processAllocApply (ApplyInst *AI, DeadEndBlocks &DEBlocks);
793
701
702
+ bool getDeadInstsAfterInitializerRemoved (
703
+ ApplyInst *AI, llvm::SmallVectorImpl<SILInstruction *> &ToDestroy);
704
+ bool removeAndReleaseArray (
705
+ SingleValueInstruction *NewArrayValue, DeadEndBlocks &DEBlocks);
706
+
794
707
bool processFunction (SILFunction &Fn) {
795
708
DeadEndBlocks DEBlocks (&Fn);
796
709
DestructorAnalysisCache.clear ();
@@ -799,19 +712,7 @@ class DeadObjectElimination : public SILFunctionTransform {
799
712
800
713
for (auto &BB : Fn) {
801
714
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)) {
815
716
if (auto *A = dyn_cast<AllocRefInst>(inst))
816
717
Changed |= processAllocRef (A);
817
718
else if (auto *A = dyn_cast<AllocStackInst>(inst))
@@ -823,6 +724,7 @@ class DeadObjectElimination : public SILFunctionTransform {
823
724
else if (auto *A = dyn_cast<ApplyInst>(inst))
824
725
Changed |= processAllocApply (A, DEBlocks);
825
726
}
727
+ deleter.cleanupDeadInstructions ();
826
728
}
827
729
return Changed;
828
730
}
@@ -840,6 +742,15 @@ class DeadObjectElimination : public SILFunctionTransform {
840
742
};
841
743
} // end anonymous namespace
842
744
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
+
843
754
bool DeadObjectElimination::processAllocRef (AllocRefInst *ARI) {
844
755
// Ok, we have an alloc_ref. Check the cache to see if we have already
845
756
// computed the destructor behavior for its SILType.
@@ -932,7 +843,7 @@ bool DeadObjectElimination::processKeyPath(KeyPathInst *KPI) {
932
843
// / If AI is the version of an initializer where we pass in either an apply or
933
844
// / an alloc_ref to initialize in place, validate that we are able to continue
934
845
// / optimizing and return To
935
- static bool getDeadInstsAfterInitializerRemoved (
846
+ bool DeadObjectElimination:: getDeadInstsAfterInitializerRemoved (
936
847
ApplyInst *AI, llvm::SmallVectorImpl<SILInstruction *> &ToDestroy) {
937
848
assert (ToDestroy.empty () && " We assume that ToDestroy is empty, so on "
938
849
" failure we can clear without worrying about the "
@@ -973,6 +884,93 @@ static bool getDeadInstsAfterInitializerRemoved(
973
884
return true ;
974
885
}
975
886
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
+
976
974
bool DeadObjectElimination::processAllocApply (ApplyInst *AI,
977
975
DeadEndBlocks &DEBlocks) {
978
976
// Currently only handle array.uninitialized
@@ -989,12 +987,10 @@ bool DeadObjectElimination::processAllocApply(ApplyInst *AI,
989
987
990
988
LLVM_DEBUG (llvm::dbgs () << " Success! Eliminating apply allocate(...).\n " );
991
989
992
- InstructionDeleter deleter;
993
990
deleter.forceDeleteWithUsers (AI);
994
991
for (auto *toDelete : instsDeadAfterInitializerRemoved) {
995
992
deleter.trackIfDead (toDelete);
996
993
}
997
- deleter.cleanupDeadInstructions ();
998
994
999
995
++DeadAllocApplyEliminated;
1000
996
return true ;
0 commit comments