@@ -943,7 +943,7 @@ void CanonicalizeOSSALifetime::findExtendedBoundary(
943
943
// / record it as a final consume.
944
944
static void
945
945
insertDestroyBeforeInstruction (SILInstruction *nextInstruction,
946
- SILValue currentDef,
946
+ SILValue currentDef, IsDeadEnd_t isDeadEnd,
947
947
CanonicalOSSAConsumeInfo &consumes,
948
948
SmallVectorImpl<DestroyValueInst *> &destroys,
949
949
InstModCallbacks &callbacks) {
@@ -974,13 +974,63 @@ insertDestroyBeforeInstruction(SILInstruction *nextInstruction,
974
974
SILBuilderWithScope builder (nextInstruction);
975
975
auto loc =
976
976
RegularLocation::getAutoGeneratedLocation (nextInstruction->getLoc ());
977
- auto *dvi = builder.createDestroyValue (loc, currentDef);
977
+ auto *dvi =
978
+ builder.createDestroyValue (loc, currentDef, DontPoisonRefs, isDeadEnd);
978
979
callbacks.createdNewInst (dvi);
979
980
consumes.recordFinalConsume (dvi);
980
981
++NumDestroysGenerated;
981
982
destroys.push_back (dvi);
982
983
}
983
984
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
+
984
1034
// / Inserts destroys along the boundary where needed and records all final
985
1035
// / consuming uses.
986
1036
// /
@@ -992,6 +1042,18 @@ insertDestroyBeforeInstruction(SILInstruction *nextInstruction,
992
1042
void CanonicalizeOSSALifetime::insertDestroysOnBoundary (
993
1043
PrunedLivenessBoundary const &boundary,
994
1044
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
+ };
995
1057
BasicBlockSet seenMergePoints (getCurrentDef ()->getFunction ());
996
1058
for (auto *instruction : boundary.lastUsers ) {
997
1059
if (destroys.contains (instruction)) {
@@ -1013,7 +1075,8 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
1013
1075
}
1014
1076
auto *insertionPoint = &*successor->begin ();
1015
1077
insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1016
- consumes, newDestroys, getCallbacks ());
1078
+ isDeadEnd (insertionPoint), consumes,
1079
+ newDestroys, getCallbacks ());
1017
1080
LLVM_DEBUG (llvm::dbgs () << " Destroy after terminator "
1018
1081
<< *instruction << " at beginning of " ;
1019
1082
successor->printID (llvm::dbgs (), false );
@@ -1022,7 +1085,8 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
1022
1085
continue ;
1023
1086
}
1024
1087
auto *insertionPoint = instruction->getNextInstruction ();
1025
- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1088
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1089
+ isDeadEnd (insertionPoint), consumes,
1026
1090
newDestroys, getCallbacks ());
1027
1091
LLVM_DEBUG (llvm::dbgs ()
1028
1092
<< " Destroy at last use " << insertionPoint << " \n " );
@@ -1031,22 +1095,25 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
1031
1095
}
1032
1096
for (auto *edgeDestination : boundary.boundaryEdges ) {
1033
1097
auto *insertionPoint = &*edgeDestination->begin ();
1034
- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1098
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1099
+ isDeadEnd (insertionPoint), consumes,
1035
1100
newDestroys, getCallbacks ());
1036
1101
LLVM_DEBUG (llvm::dbgs () << " Destroy on edge " << edgeDestination << " \n " );
1037
1102
}
1038
1103
for (auto *def : boundary.deadDefs ) {
1039
1104
if (auto *arg = dyn_cast<SILArgument>(def)) {
1040
1105
auto *insertionPoint = &*arg->getParent ()->begin ();
1041
- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1106
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1107
+ isDeadEnd (insertionPoint), consumes,
1042
1108
newDestroys, getCallbacks ());
1043
1109
LLVM_DEBUG (llvm::dbgs ()
1044
1110
<< " Destroy after dead def arg " << arg << " \n " );
1045
1111
} else {
1046
1112
auto *instruction = cast<SILInstruction>(def);
1047
1113
auto *insertionPoint = instruction->getNextInstruction ();
1048
1114
assert (insertionPoint && " def instruction was a terminator?!" );
1049
- insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
1115
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
1116
+ isDeadEnd (insertionPoint), consumes,
1050
1117
newDestroys, getCallbacks ());
1051
1118
LLVM_DEBUG (llvm::dbgs ()
1052
1119
<< " Destroy after dead def inst " << instruction << " \n " );
0 commit comments