Skip to content

Commit 10492c9

Browse files
authored
Merge pull request swiftlang#35718 from meg-gupta/dceossafixespr
Fixes for OSSA DCE
2 parents d40b950 + d3acfee commit 10492c9

File tree

7 files changed

+485
-95
lines changed

7 files changed

+485
-95
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,23 @@ bool getAllOwnedValueIntroducers(SILValue value,
10301030

10311031
OwnedValueIntroducer getSingleOwnedValueIntroducer(SILValue value);
10321032

1033+
using BaseValueSet = SmallPtrSet<SILValue, 8>;
1034+
1035+
/// Starting from \p initialScopeOperand, find all reborrows and their
1036+
/// corresponding base values, and run the visitor function \p
1037+
/// visitReborrowBaseValuePair on them.
1038+
/// Note that a reborrow phi, can have different base values based on different
1039+
/// control flow paths.
1040+
void findTransitiveReborrowBaseValuePairs(
1041+
BorrowingOperand initialScopeOperand, SILValue origBaseValue,
1042+
function_ref<void(SILPhiArgument *, SILValue)> visitReborrowBaseValuePair);
1043+
1044+
/// Given a begin_borrow visit all end_borrow users of the borrow or its
1045+
/// reborrows.
1046+
void visitTransitiveEndBorrows(
1047+
BeginBorrowInst *borrowInst,
1048+
function_ref<void(EndBorrowInst *)> visitEndBorrow);
1049+
10331050
} // namespace swift
10341051

10351052
#endif

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,3 +1278,77 @@ bool ForwardingOperand::visitForwardedValues(
12781278
return visitor(args[0]);
12791279
});
12801280
}
1281+
1282+
void swift::findTransitiveReborrowBaseValuePairs(
1283+
BorrowingOperand initialScopedOperand, SILValue origBaseValue,
1284+
function_ref<void(SILPhiArgument *, SILValue)> visitReborrowBaseValuePair) {
1285+
// We need a SetVector to make sure we don't revisit the same reborrow operand
1286+
// again.
1287+
SmallSetVector<std::tuple<Operand *, SILValue>, 4> worklist;
1288+
1289+
// Populate the worklist with reborrow and the base value
1290+
initialScopedOperand.visitScopeEndingUses([&](Operand *op) {
1291+
if (op->getOperandOwnership() == OperandOwnership::Reborrow) {
1292+
worklist.insert(std::make_tuple(op, origBaseValue));
1293+
}
1294+
return true;
1295+
});
1296+
1297+
// Size of worklist changes in this loop
1298+
for (unsigned idx = 0; idx < worklist.size(); idx++) {
1299+
Operand *reborrowOp;
1300+
SILValue baseValue;
1301+
std::tie(reborrowOp, baseValue) = worklist[idx];
1302+
1303+
BorrowingOperand borrowingOperand(reborrowOp);
1304+
assert(borrowingOperand.isReborrow());
1305+
1306+
auto *branchInst = cast<BranchInst>(reborrowOp->getUser());
1307+
auto *succBlock = branchInst->getDestBB();
1308+
auto *phiArg = cast<SILPhiArgument>(
1309+
succBlock->getArgument(reborrowOp->getOperandNumber()));
1310+
1311+
SILValue newBaseVal = baseValue;
1312+
// If the previous base value was also passed as a phi arg, that will be
1313+
// the new base value.
1314+
for (auto *arg : succBlock->getArguments()) {
1315+
if (arg->getIncomingPhiValue(branchInst->getParent()) == baseValue) {
1316+
newBaseVal = arg;
1317+
break;
1318+
}
1319+
}
1320+
1321+
// Call the visitor function
1322+
visitReborrowBaseValuePair(phiArg, newBaseVal);
1323+
1324+
BorrowedValue scopedValue(phiArg);
1325+
scopedValue.visitLocalScopeEndingUses([&](Operand *op) {
1326+
if (op->getOperandOwnership() == OperandOwnership::Reborrow) {
1327+
worklist.insert(std::make_tuple(op, newBaseVal));
1328+
}
1329+
return true;
1330+
});
1331+
}
1332+
}
1333+
1334+
void swift::visitTransitiveEndBorrows(
1335+
BeginBorrowInst *borrowInst,
1336+
function_ref<void(EndBorrowInst *)> visitEndBorrow) {
1337+
SmallSetVector<SILValue, 4> worklist;
1338+
worklist.insert(borrowInst);
1339+
1340+
while (!worklist.empty()) {
1341+
auto val = worklist.pop_back_val();
1342+
for (auto *consumingUse : val->getConsumingUses()) {
1343+
auto *consumingUser = consumingUse->getUser();
1344+
if (auto *branch = dyn_cast<BranchInst>(consumingUser)) {
1345+
auto *succBlock = branch->getSingleSuccessorBlock();
1346+
auto *phiArg = cast<SILPhiArgument>(
1347+
succBlock->getArgument(consumingUse->getOperandNumber()));
1348+
worklist.insert(phiArg);
1349+
} else {
1350+
visitEndBorrow(cast<EndBorrowInst>(consumingUser));
1351+
}
1352+
}
1353+
}
1354+
}

lib/SIL/Verifier/ReborrowVerifier.cpp

Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -39,57 +39,18 @@ bool ReborrowVerifier::verifyReborrowLifetime(SILPhiArgument *phiArg,
3939

4040
void ReborrowVerifier::verifyReborrows(BorrowingOperand initialScopedOperand,
4141
SILValue value) {
42-
SmallVector<std::tuple<Operand *, SILValue>, 4> worklist;
43-
// Initialize the worklist with borrow lifetime ending uses
44-
initialScopedOperand.visitScopeEndingUses([&](Operand *op) {
45-
worklist.emplace_back(op, value);
46-
return true;
47-
});
48-
49-
while (!worklist.empty()) {
50-
Operand *borrowLifetimeEndOp;
51-
SILValue baseVal;
52-
std::tie(borrowLifetimeEndOp, baseVal) = worklist.pop_back_val();
53-
auto *borrowLifetimeEndUser = borrowLifetimeEndOp->getUser();
54-
55-
auto borrowingOperand = BorrowingOperand::get(borrowLifetimeEndOp);
56-
if (!borrowingOperand || !borrowingOperand.isReborrow())
57-
continue;
58-
59-
if (isVisitedOp(borrowLifetimeEndOp, baseVal))
60-
continue;
61-
62-
// Process reborrow
63-
auto *branchInst = cast<BranchInst>(borrowLifetimeEndUser);
64-
for (auto *succBlock : branchInst->getSuccessorBlocks()) {
65-
auto *phiArg = cast<SILPhiArgument>(
66-
succBlock->getArgument(borrowLifetimeEndOp->getOperandNumber()));
67-
assert(phiArg->getOwnershipKind() == OwnershipKind::Guaranteed);
68-
69-
SILValue newBaseVal = baseVal;
70-
// If the previous base value was also passed as a phi arg, that will be
71-
// the new base value.
72-
for (auto *arg : succBlock->getArguments()) {
73-
if (arg->getIncomingPhiValue(branchInst->getParent()) == baseVal) {
74-
newBaseVal = arg;
75-
break;
76-
}
77-
}
78-
79-
if (isVisitedPhiArg(phiArg, newBaseVal))
80-
continue;
81-
addVisitedPhiArg(phiArg, newBaseVal);
82-
verifyReborrowLifetime(phiArg, newBaseVal);
83-
84-
// Find the scope ending uses of the guaranteed phi arg and add it to the
85-
// worklist.
86-
auto scopedValue = BorrowedValue(phiArg);
87-
assert(scopedValue);
88-
scopedValue.visitLocalScopeEndingUses([&](Operand *op) {
89-
addVisitedOp(op, newBaseVal);
90-
worklist.emplace_back(op, newBaseVal);
91-
return true;
92-
});
42+
auto visitReborrowBaseValuePair = [&](SILPhiArgument *phiArg,
43+
SILValue baseValue) {
44+
// If the (phiArg, baseValue) pair was not visited before, verify the
45+
// lifetime.
46+
auto it = reborrowToBaseValuesMap.find(phiArg);
47+
if (it == reborrowToBaseValuesMap.end() ||
48+
it->second.find(baseValue) == it->second.end()) {
49+
reborrowToBaseValuesMap[phiArg].insert(baseValue);
50+
verifyReborrowLifetime(phiArg, baseValue);
9351
}
94-
}
52+
};
53+
// For every unique reborrow/base value pair, verify the lifetime
54+
findTransitiveReborrowBaseValuePairs(initialScopedOperand, value,
55+
visitReborrowBaseValuePair);
9556
}

lib/SIL/Verifier/ReborrowVerifierPrivate.h

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,45 +31,27 @@ class ReborrowVerifier {
3131
/// A cache of dead-end basic blocks that we use to determine if we can
3232
/// ignore "leaks".
3333
DeadEndBlocks &deadEndBlocks;
34-
/// A cache map of borrow lifetime ending operands and their base value
35-
llvm::SmallDenseMap<Operand *, SILValue> visitedOps;
36-
/// A cache map of guaranteed phi args and their base value
37-
llvm::SmallDenseMap<SILPhiArgument *, SILValue> visitedPhiArgs;
3834
/// The builder that the checker uses to emit error messages, crash if asked
3935
/// for, or supply back interesting info to the caller.
4036
LinearLifetimeChecker::ErrorBuilder errorBuilder;
37+
/// A map of reborrow phi arg to its base values.
38+
/// Note that a reborrow phi arg can have different base values based on
39+
/// different control flow paths.
40+
llvm::DenseMap<SILPhiArgument *, SmallPtrSet<SILValue, 8>>
41+
reborrowToBaseValuesMap;
4142

4243
public:
4344
ReborrowVerifier(const SILFunction *func, DeadEndBlocks &deadEndBlocks,
4445
LinearLifetimeChecker::ErrorBuilder errorBuilder)
4546
: deadEndBlocks(deadEndBlocks), errorBuilder(errorBuilder) {}
4647

48+
/// Find all the reborrows of \p initialScopedOperand and verify their
49+
/// lifetime.
4750
void verifyReborrows(BorrowingOperand initialScopedOperand, SILValue value);
4851

4952
private:
5053
/// Verifies whether the reborrow's lifetime lies within its base value
5154
bool verifyReborrowLifetime(SILPhiArgument *phiArg, SILValue baseVal);
52-
53-
/// Check if the operand is visited
54-
bool isVisitedOp(Operand *op, SILValue baseVal) {
55-
return visitedOps.find(op) != visitedOps.end();
56-
}
57-
58-
/// Check if the phi arg and base value are visited
59-
bool isVisitedPhiArg(SILPhiArgument *phiArg, SILValue baseVal) {
60-
auto itPhiArg = visitedPhiArgs.find(phiArg);
61-
return itPhiArg != visitedPhiArgs.end() && (*itPhiArg).second == baseVal;
62-
}
63-
64-
/// Mark operand as visited
65-
void addVisitedOp(Operand *op, SILValue baseVal) {
66-
visitedOps.insert({op, baseVal});
67-
}
68-
69-
/// Mark guaranteed phi arg as visited
70-
void addVisitedPhiArg(SILPhiArgument *phiArg, SILValue baseVal) {
71-
visitedPhiArgs.insert({phiArg, baseVal});
72-
}
7355
};
7456

7557
} // namespace swift

0 commit comments

Comments
 (0)