Skip to content

Commit 64bad16

Browse files
authored
Merge pull request #27316 from gottesmm/pr-634f227f60306a17bbad2b205f6bc0cea46541cf
[ownership] Only allow BranchPropagatedUser to be constructed from Operands.
2 parents 439b911 + 12aa95a commit 64bad16

File tree

9 files changed

+136
-102
lines changed

9 files changed

+136
-102
lines changed

include/swift/SIL/ApplySite.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,13 @@ class ApplySite {
130130
llvm_unreachable("covered switch"); \
131131
} while (0)
132132

133+
/// Return the callee operand as a value.
134+
SILValue getCallee() const { return getCalleeOperand()->get(); }
135+
133136
/// Return the callee operand.
134-
SILValue getCallee() const { FOREACH_IMPL_RETURN(getCallee()); }
137+
const Operand *getCalleeOperand() const {
138+
FOREACH_IMPL_RETURN(getCalleeOperand());
139+
}
135140

136141
/// Return the callee value by looking through function conversions until we
137142
/// find a function_ref, partial_apply, or unrecognized callee value.

include/swift/SIL/BranchPropagatedUser.h

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,28 @@ class BranchPropagatedUser {
3131
InnerTy user;
3232

3333
public:
34-
BranchPropagatedUser(SILInstruction *inst) : user(inst) {
35-
assert(!isa<CondBranchInst>(inst));
36-
}
37-
38-
BranchPropagatedUser(CondBranchInst *cbi) : user(cbi) {}
39-
40-
BranchPropagatedUser(CondBranchInst *cbi, unsigned successorIndex)
41-
: user(cbi, successorIndex) {
42-
assert(successorIndex == CondBranchInst::TrueIdx ||
43-
successorIndex == CondBranchInst::FalseIdx);
34+
BranchPropagatedUser(Operand *op) : user() {
35+
auto *opUser = op->getUser();
36+
auto *cbi = dyn_cast<CondBranchInst>(opUser);
37+
if (!cbi) {
38+
user = InnerTy(opUser, 0);
39+
return;
40+
}
41+
unsigned operandIndex = op->getOperandNumber();
42+
if (cbi->isConditionOperandIndex(operandIndex)) {
43+
// TODO: Is this correct?
44+
user = InnerTy(cbi, CondBranchInst::TrueIdx);
45+
return;
46+
}
47+
bool isTrueOperand = cbi->isTrueOperandIndex(operandIndex);
48+
if (isTrueOperand) {
49+
user = InnerTy(cbi, CondBranchInst::TrueIdx);
50+
} else {
51+
user = InnerTy(cbi, CondBranchInst::FalseIdx);
52+
}
4453
}
54+
BranchPropagatedUser(const Operand *op)
55+
: BranchPropagatedUser(const_cast<Operand *>(op)) {}
4556

4657
BranchPropagatedUser(const BranchPropagatedUser &other) : user(other.user) {}
4758
BranchPropagatedUser &operator=(const BranchPropagatedUser &other) {
@@ -96,6 +107,19 @@ class BranchPropagatedUser {
96107
NumLowBitsAvailable =
97108
llvm::PointerLikeTypeTraits<InnerTy>::NumLowBitsAvailable
98109
};
110+
111+
private:
112+
BranchPropagatedUser(SILInstruction *inst) : user(inst) {
113+
assert(!isa<CondBranchInst>(inst));
114+
}
115+
116+
BranchPropagatedUser(CondBranchInst *cbi) : user(cbi) {}
117+
118+
BranchPropagatedUser(CondBranchInst *cbi, unsigned successorIndex)
119+
: user(cbi, successorIndex) {
120+
assert(successorIndex == CondBranchInst::TrueIdx ||
121+
successorIndex == CondBranchInst::FalseIdx);
122+
}
99123
};
100124

101125
} // namespace swift

include/swift/SIL/OwnershipUtils.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,14 +310,13 @@ struct BorrowScopeIntroducingValue {
310310
/// called with a scope that is not local.
311311
///
312312
/// The intention is that this method can be used instead of
313-
/// BorrowScopeIntroducingValue::getLocalScopeEndingInstructions() to avoid
313+
/// BorrowScopeIntroducingValue::getLocalScopeEndingUses() to avoid
314314
/// introducing an intermediate array when one needs to transform the
315315
/// instructions before storing them.
316316
///
317317
/// NOTE: To determine if a scope is a local scope, call
318318
/// BorrowScopeIntoducingValue::isLocalScope().
319-
void visitLocalScopeEndingInstructions(
320-
function_ref<void(SILInstruction *)> visitor) const;
319+
void visitLocalScopeEndingUses(function_ref<void(Operand *)> visitor) const;
321320

322321
bool isLocalScope() const { return kind.isLocalScope(); }
323322

include/swift/SIL/SILInstruction.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,7 +1861,8 @@ class ApplyInstBase<Impl, Base, false> : public Base {
18611861
/// The operand number of the first argument.
18621862
static unsigned getArgumentOperandNumber() { return NumStaticOperands; }
18631863

1864-
SILValue getCallee() const { return getAllOperands()[Callee].get(); }
1864+
const Operand *getCalleeOperand() const { return &getAllOperands()[Callee]; }
1865+
SILValue getCallee() const { return getCalleeOperand()->get(); }
18651866

18661867
/// Gets the origin of the callee by looking through function type conversions
18671868
/// until we find a function_ref, partial_apply, or unrecognized value.
@@ -7212,7 +7213,10 @@ class CondBranchInst final
72127213
ProfileCounter FalseBBCount, SILFunction &F);
72137214

72147215
public:
7215-
SILValue getCondition() const { return getAllOperands()[ConditionIdx].get(); }
7216+
const Operand *getConditionOperand() const {
7217+
return &getAllOperands()[ConditionIdx];
7218+
}
7219+
SILValue getCondition() const { return getConditionOperand()->get(); }
72167220
void setCondition(SILValue newCondition) {
72177221
getAllOperands()[ConditionIdx].set(newCondition);
72187222
}
@@ -7258,6 +7262,11 @@ class CondBranchInst final
72587262
return getAllOperands().slice(NumFixedOpers + getNumTrueArgs());
72597263
}
72607264

7265+
/// Returns true if \p op is mapped to the condition operand of the cond_br.
7266+
bool isConditionOperand(Operand *op) const {
7267+
return getConditionOperand() == op;
7268+
}
7269+
72617270
bool isConditionOperandIndex(unsigned OpIndex) const {
72627271
assert(OpIndex < getNumOperands() &&
72637272
"OpIndex must be an index for an actual operand");

lib/SIL/OwnershipUtils.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,20 +121,24 @@ void BorrowScopeIntroducingValue::getLocalScopeEndingInstructions(
121121
llvm_unreachable("Covered switch isn't covered?!");
122122
}
123123

124-
void BorrowScopeIntroducingValue::visitLocalScopeEndingInstructions(
125-
function_ref<void(SILInstruction *)> visitor) const {
124+
void BorrowScopeIntroducingValue::visitLocalScopeEndingUses(
125+
function_ref<void(Operand *)> visitor) const {
126126
assert(isLocalScope() && "Should only call this given a local scope");
127127
switch (kind) {
128128
case BorrowScopeIntroducerKind::SILFunctionArgument:
129129
llvm_unreachable("Should only call this with a local scope");
130130
case BorrowScopeIntroducerKind::BeginBorrow:
131-
for (auto *inst : cast<BeginBorrowInst>(value)->getEndBorrows()) {
132-
visitor(inst);
131+
for (auto *use : cast<BeginBorrowInst>(value)->getUses()) {
132+
if (isa<EndBorrowInst>(use->getUser())) {
133+
visitor(use);
134+
}
133135
}
134136
return;
135137
case BorrowScopeIntroducerKind::LoadBorrow:
136-
for (auto *inst : cast<LoadBorrowInst>(value)->getEndBorrows()) {
137-
visitor(inst);
138+
for (auto *use : cast<LoadBorrowInst>(value)->getUses()) {
139+
if (isa<EndBorrowInst>(use->getUser())) {
140+
visitor(use);
141+
}
138142
}
139143
return;
140144
}
@@ -203,8 +207,8 @@ bool BorrowScopeIntroducingValue::areInstructionsWithinScope(
203207
return true;
204208

205209
// Otherwise, gather up our local scope ending instructions.
206-
visitLocalScopeEndingInstructions(
207-
[&scratchSpace](SILInstruction *i) { scratchSpace.emplace_back(i); });
210+
visitLocalScopeEndingUses(
211+
[&scratchSpace](Operand *op) { scratchSpace.emplace_back(op); });
208212

209213
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
210214
return checker.validateLifetime(value, scratchSpace, instructions);

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,19 @@ class SILValueOwnershipChecker {
9393

9494
/// The list of lifetime ending users that we found. Only valid if check is
9595
/// successful.
96-
SmallVector<BranchPropagatedUser, 16> lifetimeEndingUsers;
96+
SmallVector<Operand *, 16> lifetimeEndingUsers;
9797

9898
/// The list of non lifetime ending users that we found. Only valid if check
9999
/// is successful.
100-
SmallVector<BranchPropagatedUser, 16> regularUsers;
100+
SmallVector<Operand *, 16> regularUsers;
101101

102102
/// The list of implicit non lifetime ending users that we found. This
103103
/// consists of instructions like end_borrow that end a scoped lifetime. We
104104
/// must treat those as regular uses and ensure that our value is not
105105
/// destroyed while that sub-scope is valid.
106106
///
107107
/// TODO: Rename to SubBorrowScopeUsers?
108-
SmallVector<BranchPropagatedUser, 4> implicitRegularUsers;
108+
SmallVector<Operand *, 4> implicitRegularUsers;
109109

110110
/// The set of blocks that we have visited.
111111
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
@@ -133,22 +133,25 @@ class SILValueOwnershipChecker {
133133
if (!result.getValue())
134134
return false;
135135

136+
SmallVector<BranchPropagatedUser, 32> allLifetimeEndingUsers;
137+
llvm::copy(lifetimeEndingUsers, std::back_inserter(allLifetimeEndingUsers));
136138
SmallVector<BranchPropagatedUser, 32> allRegularUsers;
137139
llvm::copy(regularUsers, std::back_inserter(allRegularUsers));
138140
llvm::copy(implicitRegularUsers, std::back_inserter(allRegularUsers));
141+
139142
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
140143
auto linearLifetimeResult = checker.checkValue(
141-
value, lifetimeEndingUsers, allRegularUsers, errorBehavior);
144+
value, allLifetimeEndingUsers, allRegularUsers, errorBehavior);
142145
result = !linearLifetimeResult.getFoundError();
143146

144147
return result.getValue();
145148
}
146149

147150
private:
148151
bool checkUses();
149-
bool gatherUsers(SmallVectorImpl<BranchPropagatedUser> &lifetimeEndingUsers,
150-
SmallVectorImpl<BranchPropagatedUser> &regularUsers,
151-
SmallVectorImpl<BranchPropagatedUser> &implicitRegularUsers);
152+
bool gatherUsers(SmallVectorImpl<Operand *> &lifetimeEndingUsers,
153+
SmallVectorImpl<Operand *> &regularUsers,
154+
SmallVectorImpl<Operand *> &implicitRegularUsers);
152155

153156
bool checkValueWithoutLifetimeEndingUses();
154157

@@ -157,10 +160,10 @@ class SILValueOwnershipChecker {
157160

158161
bool isGuaranteedFunctionArgWithLifetimeEndingUses(
159162
SILFunctionArgument *arg,
160-
const SmallVectorImpl<BranchPropagatedUser> &lifetimeEndingUsers) const;
163+
const SmallVectorImpl<Operand *> &lifetimeEndingUsers) const;
161164
bool isSubobjectProjectionWithLifetimeEndingUses(
162165
SILValue value,
163-
const SmallVectorImpl<BranchPropagatedUser> &lifetimeEndingUsers) const;
166+
const SmallVectorImpl<Operand *> &lifetimeEndingUsers) const;
164167

165168
/// Depending on our initialization, either return false or call Func and
166169
/// throw an error.
@@ -181,9 +184,9 @@ class SILValueOwnershipChecker {
181184
} // end anonymous namespace
182185

183186
bool SILValueOwnershipChecker::gatherUsers(
184-
SmallVectorImpl<BranchPropagatedUser> &lifetimeEndingUsers,
185-
SmallVectorImpl<BranchPropagatedUser> &nonLifetimeEndingUsers,
186-
SmallVectorImpl<BranchPropagatedUser> &implicitRegularUsers) {
187+
SmallVectorImpl<Operand *> &lifetimeEndingUsers,
188+
SmallVectorImpl<Operand *> &nonLifetimeEndingUsers,
189+
SmallVectorImpl<Operand *> &implicitRegularUsers) {
187190

188191
// See if Value is guaranteed. If we are guaranteed and not forwarding, then
189192
// we need to look through subobject uses for more uses. Otherwise, if we are
@@ -198,19 +201,7 @@ bool SILValueOwnershipChecker::gatherUsers(
198201

199202
// Then gather up our initial list of users.
200203
SmallVector<Operand *, 8> users;
201-
std::copy(value->use_begin(), value->use_end(), std::back_inserter(users));
202-
203-
auto addCondBranchToList = [](SmallVectorImpl<BranchPropagatedUser> &list,
204-
CondBranchInst *cbi, unsigned operandIndex) {
205-
if (cbi->isConditionOperandIndex(operandIndex)) {
206-
list.emplace_back(cbi);
207-
return;
208-
}
209-
210-
bool isTrueOperand = cbi->isTrueOperandIndex(operandIndex);
211-
list.emplace_back(cbi, isTrueOperand ? CondBranchInst::TrueIdx
212-
: CondBranchInst::FalseIdx);
213-
};
204+
llvm::copy(value->getUses(), std::back_inserter(users));
214205

215206
bool foundError = false;
216207
while (!users.empty()) {
@@ -267,19 +258,10 @@ bool SILValueOwnershipChecker::gatherUsers(
267258
opOwnershipKindMap.getLifetimeConstraint(ownershipKind);
268259
if (lifetimeConstraint == UseLifetimeConstraint::MustBeInvalidated) {
269260
LLVM_DEBUG(llvm::dbgs() << " Lifetime Ending User: " << *user);
270-
if (auto *cbi = dyn_cast<CondBranchInst>(user)) {
271-
addCondBranchToList(lifetimeEndingUsers, cbi, op->getOperandNumber());
272-
} else {
273-
lifetimeEndingUsers.emplace_back(user);
274-
}
261+
lifetimeEndingUsers.push_back(op);
275262
} else {
276263
LLVM_DEBUG(llvm::dbgs() << " Regular User: " << *user);
277-
if (auto *cbi = dyn_cast<CondBranchInst>(user)) {
278-
addCondBranchToList(nonLifetimeEndingUsers, cbi,
279-
op->getOperandNumber());
280-
} else {
281-
nonLifetimeEndingUsers.emplace_back(user);
282-
}
264+
nonLifetimeEndingUsers.push_back(op);
283265
}
284266

285267
// If our base value is not guaranteed, we do not to try to visit
@@ -296,12 +278,14 @@ bool SILValueOwnershipChecker::gatherUsers(
296278
// For correctness reasons we use indices to make sure that we can
297279
// append to NonLifetimeEndingUsers without needing to deal with
298280
// iterator invalidation.
299-
SmallVector<SILInstruction *, 4> endBorrowInsts;
300281
for (unsigned i : indices(nonLifetimeEndingUsers)) {
301282
if (auto *bbi = dyn_cast<BeginBorrowInst>(
302-
nonLifetimeEndingUsers[i].getInst())) {
303-
llvm::copy(bbi->getEndBorrows(),
304-
std::back_inserter(implicitRegularUsers));
283+
nonLifetimeEndingUsers[i]->getUser())) {
284+
for (auto *use : bbi->getUses()) {
285+
if (isa<EndBorrowInst>(use->getUser())) {
286+
implicitRegularUsers.push_back(use);
287+
}
288+
}
305289
}
306290
}
307291
}
@@ -381,8 +365,8 @@ bool SILValueOwnershipChecker::gatherUsers(
381365
// them to ensure that all of BBArg's uses are completely
382366
// enclosed within the end_borrow of this argument.
383367
for (auto *op : succArg->getUses()) {
384-
if (auto *ebi = dyn_cast<EndBorrowInst>(op->getUser())) {
385-
implicitRegularUsers.push_back(ebi);
368+
if (isa<EndBorrowInst>(op->getUser())) {
369+
implicitRegularUsers.push_back(op);
386370
}
387371
}
388372
}
@@ -493,33 +477,31 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
493477

494478
bool SILValueOwnershipChecker::isGuaranteedFunctionArgWithLifetimeEndingUses(
495479
SILFunctionArgument *arg,
496-
const llvm::SmallVectorImpl<BranchPropagatedUser> &lifetimeEndingUsers)
497-
const {
480+
const llvm::SmallVectorImpl<Operand *> &lifetimeEndingUsers) const {
498481
if (arg->getOwnershipKind() != ValueOwnershipKind::Guaranteed)
499482
return true;
500483

501484
return handleError([&] {
502485
llvm::errs() << " Function: '" << arg->getFunction()->getName() << "'\n"
503486
<< " Guaranteed function parameter with life ending uses!\n"
504487
<< " Value: " << *arg;
505-
for (const auto &user : lifetimeEndingUsers) {
506-
llvm::errs() << " Lifetime Ending User: " << *user;
488+
for (const auto *use : lifetimeEndingUsers) {
489+
llvm::errs() << " Lifetime Ending User: " << *use->getUser();
507490
}
508491
llvm::errs() << '\n';
509492
});
510493
}
511494

512495
bool SILValueOwnershipChecker::isSubobjectProjectionWithLifetimeEndingUses(
513496
SILValue value,
514-
const llvm::SmallVectorImpl<BranchPropagatedUser> &lifetimeEndingUsers)
515-
const {
497+
const llvm::SmallVectorImpl<Operand *> &lifetimeEndingUsers) const {
516498
return handleError([&] {
517499
llvm::errs() << " Function: '" << value->getFunction()->getName()
518500
<< "'\n"
519501
<< " Subobject projection with life ending uses!\n"
520502
<< " Value: " << *value;
521-
for (const auto &user : lifetimeEndingUsers) {
522-
llvm::errs() << " Lifetime Ending User: " << *user;
503+
for (const auto *use : lifetimeEndingUsers) {
504+
llvm::errs() << " Lifetime Ending User: " << *use->getUser();
523505
}
524506
llvm::errs() << '\n';
525507
});

0 commit comments

Comments
 (0)