@@ -943,7 +943,7 @@ void CanonicalizeOSSALifetime::findExtendedBoundary(
943943// / record it as a final consume.
944944static void
945945insertDestroyBeforeInstruction (SILInstruction *nextInstruction,
946- SILValue currentDef,
946+ SILValue currentDef, IsDeadEnd_t isDeadEnd,
947947 CanonicalOSSAConsumeInfo &consumes,
948948 SmallVectorImpl<DestroyValueInst *> &destroys,
949949 InstModCallbacks &callbacks) {
@@ -974,13 +974,63 @@ insertDestroyBeforeInstruction(SILInstruction *nextInstruction,
974974 SILBuilderWithScope builder (nextInstruction);
975975 auto loc =
976976 RegularLocation::getAutoGeneratedLocation (nextInstruction->getLoc ());
977- auto *dvi = builder.createDestroyValue (loc, currentDef);
977+ auto *dvi =
978+ builder.createDestroyValue (loc, currentDef, DontPoisonRefs, isDeadEnd);
978979 callbacks.createdNewInst (dvi);
979980 consumes.recordFinalConsume (dvi);
980981 ++NumDestroysGenerated;
981982 destroys.push_back (dvi);
982983}
983984
985+ // / Whether a destroy created at \p inst should be marked [dead_end].
986+ // /
987+ // / It should be if
988+ // / (1) \p inst is itself in a dead-end region
989+ // / (2) all destroys after \p inst are [dead_end]
990+ static IsDeadEnd_t
991+ isDeadEndDestroy (SILInstruction *inst,
992+ SmallPtrSetVector<SILInstruction *, 8 > const &destroys,
993+ BasicBlockSet &semanticDestroysBlocks,
994+ DeadEndBlocks *deadEnds) {
995+ auto *parent = inst->getParent ();
996+ if (!deadEnds->isDeadEnd (parent)) {
997+ // Only destroys in dead-ends can be non-meaningful (aka "dead end").
998+ return IsntDeadEnd;
999+ }
1000+ if (semanticDestroysBlocks.contains (parent)) {
1001+ // `parent` has a semantic destroy somewhere. Is it after `inst`?
1002+ for (auto *i = inst; i; i = i->getNextInstruction ()) {
1003+ if (!destroys.contains (i)) {
1004+ continue ;
1005+ }
1006+ auto *dvi = cast<DestroyValueInst>(i);
1007+ if (!dvi->isDeadEnd ()) {
1008+ // Some subsequent destroy within `parent` was meaningful, so one
1009+ // created at `inst` must be too.
1010+ return IsntDeadEnd;
1011+ }
1012+ }
1013+ }
1014+ // Walk the portion of the dead-end region after `parent` to check that all
1015+ // destroys are non-meaningful.
1016+ BasicBlockWorklist worklist (inst->getFunction ());
1017+ for (auto *successor : parent->getSuccessorBlocks ()) {
1018+ worklist.push (successor);
1019+ }
1020+ while (auto *block = worklist.pop ()) {
1021+ assert (deadEnds->isDeadEnd (block));
1022+ if (semanticDestroysBlocks.contains (block)) {
1023+ // Some subsequent destroy was meaningful, so one created at `inst`
1024+ // must be too.
1025+ return IsntDeadEnd;
1026+ }
1027+ for (auto *successor : block->getSuccessorBlocks ()) {
1028+ worklist.pushIfNotVisited (successor);
1029+ }
1030+ }
1031+ return IsDeadEnd;
1032+ }
1033+
9841034// / Inserts destroys along the boundary where needed and records all final
9851035// / consuming uses.
9861036// /
@@ -992,6 +1042,18 @@ insertDestroyBeforeInstruction(SILInstruction *nextInstruction,
9921042void CanonicalizeOSSALifetime::insertDestroysOnBoundary (
9931043 PrunedLivenessBoundary const &boundary,
9941044 SmallVectorImpl<DestroyValueInst *> &newDestroys) {
1045+ BasicBlockSet semanticDestroyBlocks (getCurrentDef ()->getFunction ());
1046+ for (auto *destroy : destroys) {
1047+ if (!cast<DestroyValueInst>(destroy)->isDeadEnd ()) {
1048+ semanticDestroyBlocks.insert (destroy->getParent ());
1049+ }
1050+ }
1051+ auto isDeadEnd = [&semanticDestroyBlocks,
1052+ this ](SILInstruction *inst) -> IsDeadEnd_t {
1053+ return isDeadEndDestroy (
1054+ inst, destroys, semanticDestroyBlocks,
1055+ deadEndBlocksAnalysis->get (getCurrentDef ()->getFunction ()));
1056+ };
9951057 BasicBlockSet seenMergePoints (getCurrentDef ()->getFunction ());
9961058 for (auto *instruction : boundary.lastUsers ) {
9971059 if (destroys.contains (instruction)) {
@@ -1013,7 +1075,8 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
10131075 }
10141076 auto *insertionPoint = &*successor->begin ();
10151077 insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1016- consumes, newDestroys, getCallbacks ());
1078+ isDeadEnd (insertionPoint), consumes,
1079+ newDestroys, getCallbacks ());
10171080 LLVM_DEBUG (llvm::dbgs () << " Destroy after terminator "
10181081 << *instruction << " at beginning of " ;
10191082 successor->printID (llvm::dbgs (), false );
@@ -1022,7 +1085,8 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
10221085 continue ;
10231086 }
10241087 auto *insertionPoint = instruction->getNextInstruction ();
1025- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1088+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1089+ isDeadEnd (insertionPoint), consumes,
10261090 newDestroys, getCallbacks ());
10271091 LLVM_DEBUG (llvm::dbgs ()
10281092 << " Destroy at last use " << insertionPoint << " \n " );
@@ -1031,22 +1095,25 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
10311095 }
10321096 for (auto *edgeDestination : boundary.boundaryEdges ) {
10331097 auto *insertionPoint = &*edgeDestination->begin ();
1034- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1098+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1099+ isDeadEnd (insertionPoint), consumes,
10351100 newDestroys, getCallbacks ());
10361101 LLVM_DEBUG (llvm::dbgs () << " Destroy on edge " << edgeDestination << " \n " );
10371102 }
10381103 for (auto *def : boundary.deadDefs ) {
10391104 if (auto *arg = dyn_cast<SILArgument>(def)) {
10401105 auto *insertionPoint = &*arg->getParent ()->begin ();
1041- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1106+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1107+ isDeadEnd (insertionPoint), consumes,
10421108 newDestroys, getCallbacks ());
10431109 LLVM_DEBUG (llvm::dbgs ()
10441110 << " Destroy after dead def arg " << arg << " \n " );
10451111 } else {
10461112 auto *instruction = cast<SILInstruction>(def);
10471113 auto *insertionPoint = instruction->getNextInstruction ();
10481114 assert (insertionPoint && " def instruction was a terminator?!" );
1049- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1115+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1116+ isDeadEnd (insertionPoint), consumes,
10501117 newDestroys, getCallbacks ());
10511118 LLVM_DEBUG (llvm::dbgs ()
10521119 << " Destroy after dead def inst " << instruction << " \n " );
0 commit comments