Skip to content

Commit 71fd7f9

Browse files
authored
Merge pull request #37003 from gottesmm/pr-af8aa6d23b297a3ff4a3237f2dfe6fec12673023
[ownership] Change CanonicalOSSALifetime to use an InstModCallback.
2 parents cd6e1af + c3c2b84 commit 71fd7f9

File tree

3 files changed

+76
-44
lines changed

3 files changed

+76
-44
lines changed

include/swift/SILOptimizer/Utils/CanonicalOSSALifetime.h

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
#include "swift/SIL/SILInstruction.h"
9898
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
9999
#include "swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h"
100+
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
100101
#include "swift/SILOptimizer/Utils/PrunedLiveness.h"
101102
#include "llvm/ADT/DenseMap.h"
102103
#include "llvm/ADT/SetVector.h"
@@ -107,13 +108,19 @@ namespace swift {
107108
/// result or invalid SILValue. The caller must delete the extract and its
108109
/// now-dead copy use.
109110
///
110-
// If a copied-def is a struct-extract, attempt a destructure conversion
111-
// %extract = struct_extract %... : $TypeWithSingleOwnershipValue
112-
// %copy = copy_value %extract : $OwnershipValue
113-
// To:
114-
// %copy = copy_value %extract : $TypeWithSingleOwnershipValue
115-
// (%extracted,...) = destructure %copy : $TypeWithSingleOwnershipValue
116-
SILValue convertExtractToDestructure(StructExtractInst *extract);
111+
/// If a copied-def is a struct-extract, attempt a destructure conversion
112+
/// %extract = struct_extract %... : $TypeWithSingleOwnershipValue
113+
/// %copy = copy_value %extract : $OwnershipValue
114+
/// To:
115+
/// %copy = copy_value %extract : $TypeWithSingleOwnershipValue
116+
/// (%extracted,...) = destructure %copy : $TypeWithSingleOwnershipValue
117+
///
118+
/// \p instModCallbacks If non-null, this routine uses
119+
/// InstModCallbacks::{setUseValue,RAUW}() internally to modify code. Otherwise,
120+
/// just performs standard operations.
121+
SILValue
122+
convertExtractToDestructure(StructExtractInst *extract,
123+
InstModCallbacks *instModCallbacks = nullptr);
117124

118125
/// Information about consumes on the extended-lifetime boundary. Consuming uses
119126
/// within the lifetime are not included--they will consume a copy after
@@ -333,16 +340,21 @@ class CanonicalizeOSSALifetime {
333340
/// lifetime.
334341
CanonicalOSSAConsumeInfo consumes;
335342

343+
/// The callbacks to use when deleting/rauwing instructions.
344+
InstModCallbacks instModCallbacks;
345+
336346
public:
337-
CanonicalizeOSSALifetime(bool pruneDebugMode, bool canonicalizeBorrowMode,
338-
bool poisonRefsMode,
339-
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
340-
DominanceAnalysis *dominanceAnalysis)
341-
: pruneDebugMode(pruneDebugMode),
342-
canonicalizeBorrowMode(canonicalizeBorrowMode),
343-
poisonRefsMode(poisonRefsMode),
344-
accessBlockAnalysis(accessBlockAnalysis),
345-
dominanceAnalysis(dominanceAnalysis) {}
347+
CanonicalizeOSSALifetime(
348+
bool pruneDebugMode, bool canonicalizeBorrowMode, bool poisonRefsMode,
349+
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
350+
DominanceAnalysis *dominanceAnalysis,
351+
InstModCallbacks instModCallbacks = InstModCallbacks())
352+
: pruneDebugMode(pruneDebugMode),
353+
canonicalizeBorrowMode(canonicalizeBorrowMode),
354+
poisonRefsMode(poisonRefsMode),
355+
accessBlockAnalysis(accessBlockAnalysis),
356+
dominanceAnalysis(dominanceAnalysis),
357+
instModCallbacks(instModCallbacks) {}
346358

347359
SILValue getCurrentDef() const { return currentDef; }
348360

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,9 @@ class InstModCallbacks {
361361
/// A function sets the value in \p use to be \p newValue.
362362
///
363363
/// Default implementation just calls use->set(newValue).
364+
///
365+
/// NOTE: It is assumed that this operation will never invalidate instruction
366+
/// iterators.
364367
std::function<void(Operand *use, SILValue newValue)> setUseValueFunc;
365368

366369
/// A boolean that tracks if any of our callbacks were ever called.

lib/SILOptimizer/Utils/CanonicalOSSALifetime.cpp

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,22 @@ SILValue CanonicalizeOSSALifetime::getCanonicalCopiedDef(SILValue v) {
9494
/// The lifetime extends beyond given consuming use. Copy the value.
9595
///
9696
/// This can set the operand value, but cannot invalidate the use iterator.
97-
static void copyLiveUse(Operand *use) {
97+
static void copyLiveUse(Operand *use, InstModCallbacks &instModCallbacks) {
9898
SILInstruction *user = use->getUser();
99-
SILBuilderWithScope B(user->getIterator());
99+
SILBuilderWithScope builder(user->getIterator());
100100

101101
auto loc = RegularLocation::getAutoGeneratedLocation(user->getLoc());
102-
auto *copy = B.createCopyValue(loc, use->get());
103-
use->set(copy);
102+
auto *copy = builder.createCopyValue(loc, use->get());
103+
instModCallbacks.createdNewInst(copy);
104+
instModCallbacks.setUseValue(use, copy);
104105

105106
++NumCopiesGenerated;
106107
LLVM_DEBUG(llvm::dbgs() << " Copying at last use " << *copy);
107108
}
108109

109110
// TODO: generalize this to handle multiple nondebug uses of the struct_extract.
110-
SILValue swift::convertExtractToDestructure(StructExtractInst *extract) {
111+
SILValue swift::convertExtractToDestructure(StructExtractInst *extract,
112+
InstModCallbacks *callbacks) {
111113
if (!hasOneNonDebugUse(extract))
112114
return nullptr;
113115

@@ -123,12 +125,20 @@ SILValue swift::convertExtractToDestructure(StructExtractInst *extract) {
123125
auto loc = extract->getLoc();
124126
auto *copy = builder.createCopyValue(loc, extract->getOperand());
125127
auto *destructure = builder.createDestructureStruct(loc, copy);
128+
if (callbacks) {
129+
callbacks->createdNewInst(copy);
130+
callbacks->createdNewInst(destructure);
131+
}
126132

127133
SILValue nonTrivialResult = destructure->getResult(extract->getFieldIndex());
128134
assert(!nonTrivialResult->getType().isTrivial(*destructure->getFunction())
129135
&& "field idx mismatch");
130136

131-
extractCopy->replaceAllUsesWith(nonTrivialResult);
137+
if (callbacks) {
138+
callbacks->replaceValueUsesWith(extractCopy, nonTrivialResult);
139+
} else {
140+
extractCopy->replaceAllUsesWith(nonTrivialResult);
141+
}
132142
return nonTrivialResult;
133143
}
134144

@@ -176,11 +186,13 @@ bool CanonicalizeOSSALifetime::computeBorrowLiveness() {
176186
// To use an existing outer copy, we could find its earliest consume. But the
177187
// new copy will immediately canonicalized and a canonical begin_borrow scope
178188
// have no outer uses of its first block.
179-
static CopyValueInst *createOuterCopy(BeginBorrowInst *beginBorrow) {
180-
SILBuilderWithScope B(beginBorrow);
189+
static CopyValueInst *createOuterCopy(BeginBorrowInst *beginBorrow,
190+
InstModCallbacks &instModCallbacks) {
191+
SILBuilderWithScope builder(beginBorrow);
181192

182193
auto loc = RegularLocation::getAutoGeneratedLocation(beginBorrow->getLoc());
183-
auto *copy = B.createCopyValue(loc, beginBorrow->getOperand());
194+
auto *copy = builder.createCopyValue(loc, beginBorrow->getOperand());
195+
instModCallbacks.createdNewInst(copy);
184196

185197
++NumCopiesGenerated;
186198
LLVM_DEBUG(llvm::dbgs() << " Outer copy " << *copy);
@@ -346,7 +358,7 @@ void CanonicalizeOSSALifetime::rewriteOuterBorrowUsesAndFindConsumes(
346358

347359
auto rewriteOuterUse = [&](Operand *use) {
348360
LLVM_DEBUG(llvm::dbgs() << " Use of outer copy " << *use->getUser());
349-
use->set(newIncomingValue);
361+
instModCallbacks.setUseValue(use, newIncomingValue);
350362
currentOuterUseInsts.push_back(use->getUser());
351363
outerUseInsts.insert(incomingValue->getDefiningInstruction());
352364
if (use->isLifetimeEnding()) {
@@ -444,18 +456,19 @@ void CanonicalizeOSSALifetime::rewriteOuterBorrowUsesAndFindConsumes(
444456
for (auto *boundaryEdge : boundary.boundaryEdges) {
445457
if (DeadEndBlocks::triviallyEndsInUnreachable(boundaryEdge))
446458
continue;
447-
448459
auto insertPt = boundaryEdge->begin();
449-
auto loc = insertPt->getLoc();
450-
SILBuilderWithScope(insertPt).createDestroyValue(loc, newIncomingValue);
460+
auto *dvi = SILBuilderWithScope(insertPt).createDestroyValue(
461+
insertPt->getLoc(), newIncomingValue);
462+
instModCallbacks.createdNewInst(dvi);
451463
}
452464

453465
for (SILInstruction *lastUser : boundary.lastUsers) {
454466
if (unclaimedConsumingUsers.erase(lastUser))
455467
continue;
456468

457469
SILBuilderWithScope::insertAfter(lastUser, [&](SILBuilder &b) {
458-
b.createDestroyValue(lastUser->getLoc(), newIncomingValue);
470+
auto *dvi = b.createDestroyValue(lastUser->getLoc(), newIncomingValue);
471+
instModCallbacks.createdNewInst(dvi);
459472
});
460473
}
461474
// Add copies for consuming users of newIncomingValue.
@@ -466,7 +479,7 @@ void CanonicalizeOSSALifetime::rewriteOuterBorrowUsesAndFindConsumes(
466479
// unclaimedConsumingUsers set after skipping the first copy.
467480
auto iterAndInserted = unclaimedConsumingUsers.insert(use->getUser());
468481
if (!iterAndInserted.second) {
469-
copyLiveUse(use);
482+
copyLiveUse(use, instModCallbacks);
470483
}
471484
}
472485
}
@@ -496,7 +509,8 @@ bool CanonicalizeOSSALifetime::consolidateBorrowScope() {
496509
if (outerUseInsts.empty()) {
497510
return true;
498511
}
499-
this->outerCopy = createOuterCopy(cast<BeginBorrowInst>(currentDef));
512+
this->outerCopy =
513+
createOuterCopy(cast<BeginBorrowInst>(currentDef), instModCallbacks);
500514

501515
defUseWorklist.clear();
502516
rewriteOuterBorrowUsesAndFindConsumes(currentDef, outerUseInsts);
@@ -761,6 +775,7 @@ void CanonicalizeOSSALifetime::insertDestroyOnCFGEdge(
761775
SILBuilderWithScope builder(pos);
762776
auto loc = RegularLocation::getAutoGeneratedLocation(pos->getLoc());
763777
auto *di = builder.createDestroyValue(loc, currentDef, needsPoison);
778+
instModCallbacks.createdNewInst(di);
764779

765780
consumes.recordFinalConsume(di);
766781

@@ -772,9 +787,10 @@ void CanonicalizeOSSALifetime::insertDestroyOnCFGEdge(
772787
///
773788
/// Create a final destroy, immediately after `pos`.
774789
static void insertDestroyAtInst(SILBasicBlock::iterator pos,
775-
DestroyValueInst *existingDestroy,
776-
SILValue def, bool needsPoison,
777-
CanonicalOSSAConsumeInfo &consumes) {
790+
DestroyValueInst *existingDestroy, SILValue def,
791+
bool needsPoison,
792+
CanonicalOSSAConsumeInfo &consumes,
793+
InstModCallbacks &callbacks) {
778794
if (existingDestroy) {
779795
for (; pos != existingDestroy->getIterator(); ++pos) {
780796
if (auto *debugVal = dyn_cast<DebugValueInst>(&*pos)) {
@@ -791,6 +807,7 @@ static void insertDestroyAtInst(SILBasicBlock::iterator pos,
791807
SILBuilderWithScope builder(pos);
792808
auto loc = RegularLocation::getAutoGeneratedLocation((*pos).getLoc());
793809
auto *di = builder.createDestroyValue(loc, def, needsPoison);
810+
callbacks.createdNewInst(di);
794811
consumes.recordFinalConsume(di);
795812

796813
++NumDestroysGenerated;
@@ -837,7 +854,7 @@ void CanonicalizeOSSALifetime::findOrInsertDestroyInBlock(SILBasicBlock *bb) {
837854
needsPoison = existingDestroyNeedsPoison;
838855
}
839856
insertDestroyAtInst(std::next(instIter), existingDestroy, currentDef,
840-
needsPoison, consumes);
857+
needsPoison, consumes, instModCallbacks);
841858
setChanged();
842859
}
843860
return;
@@ -889,7 +906,7 @@ void CanonicalizeOSSALifetime::findOrInsertDestroyInBlock(SILBasicBlock *bb) {
889906
needsPoison = existingDestroyNeedsPoison;
890907
}
891908
insertDestroyAtInst(instIter, existingDestroy, currentDef, needsPoison,
892-
consumes);
909+
consumes, instModCallbacks);
893910
setChanged();
894911
return;
895912
}
@@ -901,7 +918,7 @@ void CanonicalizeOSSALifetime::findOrInsertDestroyInBlock(SILBasicBlock *bb) {
901918
needsPoison = existingDestroyNeedsPoison;
902919
}
903920
insertDestroyAtInst(std::next(instIter), existingDestroy, currentDef,
904-
needsPoison, consumes);
921+
needsPoison, consumes, instModCallbacks);
905922
setChanged();
906923
return;
907924
}
@@ -1033,7 +1050,7 @@ void CanonicalizeOSSALifetime::rewriteCopies() {
10331050
continue;
10341051
}
10351052
if (!visitUse(use)) {
1036-
copyLiveUse(use);
1053+
copyLiveUse(use, instModCallbacks);
10371054
setChanged();
10381055
}
10391056
}
@@ -1047,16 +1064,16 @@ void CanonicalizeOSSALifetime::rewriteCopies() {
10471064
if (!reusedCopyOp && srcCopy->getParent() == use->getParentBlock()) {
10481065
reusedCopyOp = use;
10491066
} else {
1050-
copyLiveUse(use);
1067+
copyLiveUse(use, instModCallbacks);
10511068
setChanged();
10521069
}
10531070
}
10541071
}
10551072
if (!(reusedCopyOp && srcCopy->hasOneUse())) {
10561073
setChanged();
1057-
srcCopy->replaceAllUsesWith(srcCopy->getOperand());
1074+
instModCallbacks.replaceValueUsesWith(srcCopy, srcCopy->getOperand());
10581075
if (reusedCopyOp) {
1059-
reusedCopyOp->set(srcCopy);
1076+
instModCallbacks.setUseValue(reusedCopyOp, srcCopy);
10601077
} else {
10611078
if (instsToDelete.insert(srcCopy)) {
10621079
LLVM_DEBUG(llvm::dbgs() << " Removing " << *srcCopy);
@@ -1081,7 +1098,7 @@ void CanonicalizeOSSALifetime::rewriteCopies() {
10811098
// Remove any dead, non-recovered debug_values.
10821099
for (auto *dvi : consumes.getDebugInstsAfterConsume()) {
10831100
LLVM_DEBUG(llvm::dbgs() << " Removing debug_value: " << *dvi);
1084-
dvi->eraseFromParent();
1101+
instModCallbacks.deleteInst(dvi);
10851102
}
10861103

10871104
// Remove the leftover copy_value and destroy_value instructions.
@@ -1100,7 +1117,7 @@ void CanonicalizeOSSALifetime::injectPoison() {
11001117
builder.getInsertionPoint()->getLoc());
11011118
auto *di = builder.createDestroyValue(loc, currentDef,
11021119
/*needsPoison*/ true);
1103-
1120+
instModCallbacks.createdNewInst(di);
11041121
++NumDestroysGenerated;
11051122
LLVM_DEBUG(llvm::dbgs() << " Destroy at last use " << *di);
11061123
};

0 commit comments

Comments
 (0)