Skip to content

Commit 8626cc4

Browse files
authored
Merge pull request #29875 from gottesmm/pr-a905499d41ad40cb3a8a3deb651d2dd2fc3f8ad6
[ownership] Implement movable guaranteed scopes in ossa.
2 parents c4203dd + d66d329 commit 8626cc4

File tree

14 files changed

+1064
-152
lines changed

14 files changed

+1064
-152
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,22 +199,30 @@ bool isValueAddressOrTrivial(SILValue v);
199199
/// These operations forward both owned and guaranteed ownership.
200200
bool isOwnershipForwardingValueKind(SILNodeKind kind);
201201

202+
/// Is this an instruction that can forward both owned and guaranteed ownership
203+
/// kinds.
204+
bool isOwnershipForwardingInst(SILInstruction *i);
205+
206+
/// Is this an instruction that can forward guaranteed ownership.
207+
bool isGuaranteedForwardingInst(SILInstruction *i);
208+
202209
/// These operations forward guaranteed ownership, but don't necessarily forward
203210
/// owned values.
204211
bool isGuaranteedForwardingValueKind(SILNodeKind kind);
205212

213+
/// Is this a value that is the result of an operation that forwards owned
214+
/// ownership.
206215
bool isGuaranteedForwardingValue(SILValue value);
207216

208-
bool isOwnershipForwardingInst(SILInstruction *i);
209-
210-
bool isGuaranteedForwardingInst(SILInstruction *i);
217+
/// Is this a node kind that can forward owned ownership, but may not be able to
218+
/// forward guaranteed ownership.
219+
bool isOwnedForwardingValueKind(SILNodeKind kind);
211220

212221
struct BorrowScopeOperandKind {
213-
using UnderlyingKindTy = std::underlying_type<SILInstructionKind>::type;
214-
215-
enum Kind : UnderlyingKindTy {
216-
BeginBorrow = UnderlyingKindTy(SILInstructionKind::BeginBorrowInst),
217-
BeginApply = UnderlyingKindTy(SILInstructionKind::BeginApplyInst),
222+
enum Kind {
223+
BeginBorrow,
224+
BeginApply,
225+
Branch,
218226
};
219227

220228
Kind value;
@@ -232,6 +240,8 @@ struct BorrowScopeOperandKind {
232240
return BorrowScopeOperandKind(BeginBorrow);
233241
case SILInstructionKind::BeginApplyInst:
234242
return BorrowScopeOperandKind(BeginApply);
243+
case SILInstructionKind::BranchInst:
244+
return BorrowScopeOperandKind(Branch);
235245
}
236246
}
237247

@@ -242,9 +252,15 @@ struct BorrowScopeOperandKind {
242252
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
243253
BorrowScopeOperandKind kind);
244254

255+
struct BorrowScopeIntroducingValue;
256+
245257
/// An operand whose user instruction introduces a new borrow scope for the
246258
/// operand's value. The value of the operand must be considered as implicitly
247259
/// borrowed until the user's corresponding end scope instruction.
260+
///
261+
/// NOTE: We do not require that the guaranteed scope be represented by a
262+
/// guaranteed value in the same function: see begin_apply. In such cases, we
263+
/// require instead an end_* instruction to mark the end of the scope's region.
248264
struct BorrowScopeOperand {
249265
BorrowScopeOperandKind kind;
250266
Operand *op;
@@ -270,6 +286,66 @@ struct BorrowScopeOperand {
270286

271287
void visitEndScopeInstructions(function_ref<void(Operand *)> func) const;
272288

289+
/// Returns true if this borrow scope operand consumes guaranteed
290+
/// values and produces a new scope afterwards.
291+
bool consumesGuaranteedValues() const {
292+
switch (kind) {
293+
case BorrowScopeOperandKind::BeginBorrow:
294+
case BorrowScopeOperandKind::BeginApply:
295+
return false;
296+
case BorrowScopeOperandKind::Branch:
297+
return true;
298+
}
299+
llvm_unreachable("Covered switch isn't covered?!");
300+
}
301+
302+
/// Is this a borrow scope operand that can open new borrow scopes
303+
/// for owned values.
304+
bool canAcceptOwnedValues() const {
305+
switch (kind) {
306+
case BorrowScopeOperandKind::BeginBorrow:
307+
case BorrowScopeOperandKind::BeginApply:
308+
return true;
309+
case BorrowScopeOperandKind::Branch:
310+
return false;
311+
}
312+
llvm_unreachable("Covered switch isn't covered?!");
313+
}
314+
315+
/// Is the result of this instruction also a borrow introducer?
316+
///
317+
/// TODO: This needs a better name.
318+
bool areAnyUserResultsBorrowIntroducers() const {
319+
// TODO: Can we derive this by running a borrow introducer check ourselves?
320+
switch (kind) {
321+
case BorrowScopeOperandKind::BeginBorrow:
322+
case BorrowScopeOperandKind::Branch:
323+
return true;
324+
case BorrowScopeOperandKind::BeginApply:
325+
return false;
326+
}
327+
llvm_unreachable("Covered switch isn't covered?!");
328+
}
329+
330+
/// Visit all of the results of the operand's user instruction that are
331+
/// consuming uses.
332+
void visitUserResultConsumingUses(function_ref<void(Operand *)> visitor);
333+
334+
/// Visit all of the "results" of the user of this operand that are borrow
335+
/// scope introducers for the specific scope that this borrow scope operand
336+
/// summarizes.
337+
void visitBorrowIntroducingUserResults(
338+
function_ref<void(BorrowScopeIntroducingValue)> visitor);
339+
340+
/// Passes to visitor all of the consuming uses of this use's using
341+
/// instruction.
342+
///
343+
/// This enables one to walk the def-use chain of guaranteed phis for a single
344+
/// guaranteed scope by using a worklist and checking if any of the operands
345+
/// are BorrowScopeOperands.
346+
void visitConsumingUsesOfBorrowIntroducingUserResults(
347+
function_ref<void(Operand *)> visitor);
348+
273349
void print(llvm::raw_ostream &os) const;
274350
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
275351

@@ -287,10 +363,11 @@ struct BorrowScopeIntroducingValueKind {
287363
using UnderlyingKindTy = std::underlying_type<ValueKind>::type;
288364

289365
/// Enum we use for exhaustive pattern matching over borrow scope introducers.
290-
enum Kind : UnderlyingKindTy {
291-
LoadBorrow = UnderlyingKindTy(ValueKind::LoadBorrowInst),
292-
BeginBorrow = UnderlyingKindTy(ValueKind::BeginBorrowInst),
293-
SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument),
366+
enum Kind {
367+
LoadBorrow,
368+
BeginBorrow,
369+
SILFunctionArgument,
370+
Phi,
294371
};
295372

296373
static Optional<BorrowScopeIntroducingValueKind> get(ValueKind kind) {
@@ -303,6 +380,8 @@ struct BorrowScopeIntroducingValueKind {
303380
return BorrowScopeIntroducingValueKind(BeginBorrow);
304381
case ValueKind::SILFunctionArgument:
305382
return BorrowScopeIntroducingValueKind(SILFunctionArgument);
383+
case ValueKind::SILPhiArgument:
384+
return BorrowScopeIntroducingValueKind(Phi);
306385
}
307386
}
308387

@@ -323,6 +402,7 @@ struct BorrowScopeIntroducingValueKind {
323402
switch (value) {
324403
case BorrowScopeIntroducingValueKind::BeginBorrow:
325404
case BorrowScopeIntroducingValueKind::LoadBorrow:
405+
case BorrowScopeIntroducingValueKind::Phi:
326406
return true;
327407
case BorrowScopeIntroducingValueKind::SILFunctionArgument:
328408
return false;
@@ -365,9 +445,28 @@ struct BorrowScopeIntroducingValue {
365445
: kind(BorrowScopeIntroducingValueKind::SILFunctionArgument), value(arg) {
366446
assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed);
367447
}
448+
BorrowScopeIntroducingValue(SILPhiArgument *arg)
449+
: kind(BorrowScopeIntroducingValueKind::Phi), value(arg) {
450+
assert(llvm::all_of(arg->getParent()->getPredecessorBlocks(),
451+
[](SILBasicBlock *block) {
452+
return isa<BranchInst>(block->getTerminator());
453+
}) &&
454+
"Phi argument incoming values must come from branch insts!");
455+
assert(arg->isPhiArgument() && "Can only accept a true phi argument!");
456+
assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed);
457+
}
368458

369459
BorrowScopeIntroducingValue(SILValue v)
370460
: kind(*BorrowScopeIntroducingValueKind::get(v->getKind())), value(v) {
461+
// Validate that if we have a phi argument that all our predecessors have
462+
// branches as terminators.
463+
assert(!isa<SILPhiArgument>(v) ||
464+
(llvm::all_of(v->getParentBlock()->getPredecessorBlocks(),
465+
[](SILBasicBlock *block) {
466+
return isa<BranchInst>(block->getTerminator());
467+
}) &&
468+
"Phi argument incoming values must come from branch insts!"));
469+
371470
assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed);
372471
}
373472

@@ -376,6 +475,15 @@ struct BorrowScopeIntroducingValue {
376475
auto kind = BorrowScopeIntroducingValueKind::get(value->getKind());
377476
if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed)
378477
return None;
478+
// If kind is phi and we were not passed something with all branch
479+
// predecessors, return None.
480+
if ((*kind) == BorrowScopeIntroducingValueKind::Phi &&
481+
llvm::any_of(value->getParentBlock()->getPredecessorBlocks(),
482+
[](SILBasicBlock *block) {
483+
return !isa<BranchInst>(block->getTerminator());
484+
}))
485+
return None;
486+
// Otherwise, create our value directly.
379487
return BorrowScopeIntroducingValue(*kind, value);
380488
}
381489

@@ -414,6 +522,11 @@ struct BorrowScopeIntroducingValue {
414522
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
415523
DeadEndBlocks &deadEndBlocks) const;
416524

525+
/// Given a local borrow scope introducer, visit all non-forwarding consuming
526+
/// users. This means that this looks through guaranteed block arguments.
527+
bool visitLocalScopeTransitiveEndingUses(
528+
function_ref<void(Operand *)> visitor) const;
529+
417530
void print(llvm::raw_ostream &os) const;
418531
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
419532

lib/SIL/OperandOwnership.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,19 @@ OperandOwnershipKindClassifier::checkTerminatorArgumentMatchesDestBB(
415415

416416
OperandOwnershipKindMap
417417
OperandOwnershipKindClassifier::visitBranchInst(BranchInst *bi) {
418-
return checkTerminatorArgumentMatchesDestBB(bi->getDestBB(),
419-
getOperandIndex());
418+
ValueOwnershipKind destBlockArgOwnershipKind =
419+
bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind();
420+
421+
// If we have a guaranteed parameter, treat this as consuming.
422+
if (destBlockArgOwnershipKind == ValueOwnershipKind::Guaranteed) {
423+
return Map::compatibilityMap(destBlockArgOwnershipKind,
424+
UseLifetimeConstraint::MustBeInvalidated);
425+
}
426+
427+
// Otherwise, defer to defaults.
428+
auto lifetimeConstraint =
429+
destBlockArgOwnershipKind.getForwardingLifetimeConstraint();
430+
return Map::compatibilityMap(destBlockArgOwnershipKind, lifetimeConstraint);
420431
}
421432

422433
OperandOwnershipKindMap

0 commit comments

Comments
 (0)