Skip to content

Commit f0dbb8c

Browse files
authored
Merge pull request #39230 from meg-gupta/fixlba
2 parents ad533f8 + 4f2d4d5 commit f0dbb8c

File tree

6 files changed

+87
-24
lines changed

6 files changed

+87
-24
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ SILValue getAccessBase(SILValue address);
171171
/// AccessedStorage::getRoot() and AccessPath::getRoot().
172172
SILValue findReferenceRoot(SILValue ref);
173173

174+
/// Find the first owned root of the reference.
175+
SILValue findOwnershipReferenceRoot(SILValue ref);
176+
174177
/// Return true if \p address points to a let-variable.
175178
///
176179
/// let-variables are only written during let-variable initialization, which is
@@ -1264,9 +1267,13 @@ SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);
12641267

12651268
namespace swift {
12661269

1267-
/// Return true if \p svi is a cast that preserves the identity and
1270+
/// Return true if \p svi is a cast that preserves the identity equivalence of
1271+
/// the reference at operand zero.
1272+
bool isIdentityPreservingRefCast(SingleValueInstruction *svi);
1273+
1274+
/// Return true if \p svi is a cast that preserves the identity equivalence and
12681275
/// reference-counting equivalence of the reference at operand zero.
1269-
bool isRCIdentityPreservingCast(SingleValueInstruction *svi);
1276+
bool isIdentityAndOwnershipPreservingRefCast(SingleValueInstruction *svi);
12701277

12711278
/// If \p svi is an access projection, return an address-type operand for the
12721279
/// incoming address.

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,9 @@ SILValue swift::stripCastsWithoutMarkDependence(SILValue v) {
125125
return v;
126126

127127
if (auto *svi = dyn_cast<SingleValueInstruction>(v)) {
128-
if (isRCIdentityPreservingCast(svi)
129-
|| isa<UncheckedTrivialBitCastInst>(v)
130-
|| isa<BeginAccessInst>(v)
131-
|| isa<EndCOWMutationInst>(v)) {
128+
if (isIdentityPreservingRefCast(svi) ||
129+
isa<UncheckedTrivialBitCastInst>(v) || isa<BeginAccessInst>(v) ||
130+
isa<EndCOWMutationInst>(v)) {
132131
v = svi->getOperand(0);
133132
continue;
134133
}
@@ -141,10 +140,9 @@ SILValue swift::stripCasts(SILValue v) {
141140
while (true) {
142141
v = stripSinglePredecessorArgs(v);
143142
if (auto *svi = dyn_cast<SingleValueInstruction>(v)) {
144-
if (isRCIdentityPreservingCast(svi)
145-
|| isa<UncheckedTrivialBitCastInst>(v)
146-
|| isa<MarkDependenceInst>(v)
147-
|| isa<BeginAccessInst>(v)) {
143+
if (isIdentityPreservingRefCast(svi) ||
144+
isa<UncheckedTrivialBitCastInst>(v) || isa<MarkDependenceInst>(v) ||
145+
isa<BeginAccessInst>(v)) {
148146
v = cast<SingleValueInstruction>(v)->getOperand(0);
149147
continue;
150148
}

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ bool swift::isLetAddress(SILValue address) {
365365
// MARK: FindReferenceRoot
366366
//===----------------------------------------------------------------------===//
367367

368+
bool swift::isIdentityPreservingRefCast(SingleValueInstruction *svi) {
369+
// Ignore both copies and other identity and ownership preserving casts
370+
return isa<CopyValueInst>(svi) ||
371+
isIdentityAndOwnershipPreservingRefCast(svi);
372+
}
373+
368374
// On some platforms, casting from a metatype to a reference type dynamically
369375
// allocates a ref-counted box for the metatype. Naturally that is the place
370376
// where RC-identity begins. Considering the source of such a casts to be
@@ -374,12 +380,12 @@ bool swift::isLetAddress(SILValue address) {
374380
// The SILVerifier checks that none of these operations cast a trivial value to
375381
// a reference except unconditional_checked_cast[_value], which is checked By
376382
// SILDynamicCastInst::isRCIdentityPreserving().
377-
bool swift::isRCIdentityPreservingCast(SingleValueInstruction *svi) {
383+
bool swift::isIdentityAndOwnershipPreservingRefCast(
384+
SingleValueInstruction *svi) {
378385
switch (svi->getKind()) {
379386
default:
380387
return false;
381-
// Ignore ownership casts
382-
case SILInstructionKind::CopyValueInst:
388+
// Ignore borrows
383389
case SILInstructionKind::BeginBorrowInst:
384390
// Ignore class type casts
385391
case SILInstructionKind::UpcastInst:
@@ -402,8 +408,12 @@ namespace {
402408
// Essentially RC identity where the starting point is already a reference.
403409
class FindReferenceRoot {
404410
SmallPtrSet<SILPhiArgument *, 4> visitedPhis;
411+
bool preserveOwnership;
405412

406413
public:
414+
FindReferenceRoot(bool preserveOwnership)
415+
: preserveOwnership(preserveOwnership) {}
416+
407417
SILValue findRoot(SILValue ref) && {
408418
SILValue root = recursiveFindRoot(ref);
409419
assert(root && "all phi inputs must be reachable");
@@ -414,8 +424,15 @@ class FindReferenceRoot {
414424
// Return an invalid value for a phi with no resolved inputs.
415425
SILValue recursiveFindRoot(SILValue ref) {
416426
while (auto *svi = dyn_cast<SingleValueInstruction>(ref)) {
417-
if (!isRCIdentityPreservingCast(svi)) {
418-
break;
427+
// If preserveOwnership is true, stop at the first owned root
428+
if (preserveOwnership) {
429+
if (!isIdentityAndOwnershipPreservingRefCast(svi)) {
430+
break;
431+
}
432+
} else {
433+
if (!isIdentityPreservingRefCast(svi)) {
434+
break;
435+
}
419436
}
420437
ref = svi->getOperand(0);
421438
};
@@ -451,7 +468,11 @@ class FindReferenceRoot {
451468
} // end anonymous namespace
452469

453470
SILValue swift::findReferenceRoot(SILValue ref) {
454-
return FindReferenceRoot().findRoot(ref);
471+
return FindReferenceRoot(false /*preserveOwnership*/).findRoot(ref);
472+
}
473+
474+
SILValue swift::findOwnershipReferenceRoot(SILValue ref) {
475+
return FindReferenceRoot(true /*preserveOwnership*/).findRoot(ref);
455476
}
456477

457478
//===----------------------------------------------------------------------===//
@@ -1340,7 +1361,7 @@ AccessPathDefUseTraversal::UseKind
13401361
AccessPathDefUseTraversal::visitSingleValueUser(SingleValueInstruction *svi,
13411362
DFSEntry dfs) {
13421363
if (dfs.isRef()) {
1343-
if (isRCIdentityPreservingCast(svi)) {
1364+
if (isIdentityPreservingRefCast(svi)) {
13441365
pushUsers(svi, dfs);
13451366
return IgnoredUse;
13461367
}

lib/SIL/Verifier/LoadBorrowImmutabilityChecker.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ LoadBorrowImmutabilityAnalysis::LoadBorrowImmutabilityAnalysis(
292292
// \p address may be an address, pointer, or box type.
293293
bool LoadBorrowImmutabilityAnalysis::isImmutableInScope(
294294
LoadBorrowInst *lbi, ArrayRef<Operand *> endBorrowUses,
295-
AccessPath accessPath) {
296-
295+
AccessPathWithBase accessPathWithBase) {
296+
auto accessPath = accessPathWithBase.accessPath;
297297
LinearLifetimeChecker checker(deadEndBlocks);
298298
auto writes = cache.get(accessPath);
299299

@@ -303,12 +303,21 @@ bool LoadBorrowImmutabilityAnalysis::isImmutableInScope(
303303
accessPath.getStorage().print(llvm::errs());
304304
return false;
305305
}
306+
auto ownershipRoot = accessPath.getStorage().isReference()
307+
? findOwnershipReferenceRoot(accessPathWithBase.base)
308+
: SILValue();
306309
// Then for each write...
307310
for (auto *op : *writes) {
308311
// First see if the write is a dead end block. In such a case, just skip it.
309312
if (deadEndBlocks.isDeadEnd(op->getUser()->getParent())) {
310313
continue;
311314
}
315+
// A destroy_value will be a definite write only when the destroy is on the
316+
// ownershipRoot
317+
if (isa<DestroyValueInst>(op->getUser())) {
318+
if (op->get() != ownershipRoot)
319+
continue;
320+
}
312321
// See if the write is within the load borrow's lifetime. If it isn't, we
313322
// don't have to worry about it.
314323
if (!checker.validateLifetime(lbi, endBorrowUses, op)) {
@@ -326,7 +335,9 @@ bool LoadBorrowImmutabilityAnalysis::isImmutableInScope(
326335
//===----------------------------------------------------------------------===//
327336

328337
bool LoadBorrowImmutabilityAnalysis::isImmutable(LoadBorrowInst *lbi) {
329-
AccessPath accessPath = AccessPath::computeInScope(lbi->getOperand());
338+
auto accessPathWithBase = AccessPathWithBase::compute(lbi->getOperand());
339+
auto accessPath = accessPathWithBase.accessPath;
340+
330341
// Bail on an invalid AccessPath. AccessPath completeness is verified
331342
// independently--it may be invalid in extraordinary situations. When
332343
// AccessPath is valid, we know all its uses are recognizable.
@@ -358,15 +369,15 @@ bool LoadBorrowImmutabilityAnalysis::isImmutable(LoadBorrowInst *lbi) {
358369
//
359370
// TODO: As a separate analysis, verify that the load_borrow scope is always
360371
// nested within the begin_access scope (to ensure no aliasing access).
361-
return isImmutableInScope(lbi, endBorrowUses, accessPath);
372+
return isImmutableInScope(lbi, endBorrowUses, accessPathWithBase);
362373
}
363374
case AccessedStorage::Argument: {
364375
auto *arg =
365376
cast<SILFunctionArgument>(accessPath.getStorage().getArgument());
366377
if (arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)) {
367378
return true;
368379
}
369-
return isImmutableInScope(lbi, endBorrowUses, accessPath);
380+
return isImmutableInScope(lbi, endBorrowUses, accessPathWithBase);
370381
}
371382
// FIXME: A yielded address could overlap with another in this function.
372383
case AccessedStorage::Yield:
@@ -376,7 +387,7 @@ bool LoadBorrowImmutabilityAnalysis::isImmutable(LoadBorrowInst *lbi) {
376387
case AccessedStorage::Tail:
377388
case AccessedStorage::Global:
378389
case AccessedStorage::Unidentified:
379-
return isImmutableInScope(lbi, endBorrowUses, accessPath);
390+
return isImmutableInScope(lbi, endBorrowUses, accessPathWithBase);
380391
}
381392
llvm_unreachable("Covered switch isn't covered?!");
382393
}

lib/SIL/Verifier/VerifierPrivate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class LoadBorrowImmutabilityAnalysis {
4141
private:
4242
bool isImmutableInScope(LoadBorrowInst *lbi,
4343
ArrayRef<Operand *> endBorrowUses,
44-
AccessPath accessPath);
44+
AccessPathWithBase accessPathWithBase);
4545
};
4646

4747
} // namespace silverifier

test/SIL/ownership-verifier/load_borrow_invalidation_test.sil

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,3 +428,29 @@ bb0(%0 : @owned $Builtin.NativeObject):
428428
%9999 = tuple()
429429
return %9999 : $()
430430
}
431+
432+
class ComplexStruct {
433+
var val : NonTrivialStruct
434+
}
435+
436+
class Klass {
437+
}
438+
439+
struct NonTrivialStruct {
440+
var val : Klass
441+
}
442+
443+
sil [ossa] @test_borrow : $@convention(thin) (@owned ComplexStruct) -> () {
444+
bb0(%0 : @owned $ComplexStruct):
445+
%2 = copy_value %0 : $ComplexStruct
446+
%4 = begin_borrow %2 : $ComplexStruct
447+
%5 = ref_element_addr %4 : $ComplexStruct, #ComplexStruct.val
448+
%6 = load_borrow %5 : $*NonTrivialStruct
449+
destroy_value %0 : $ComplexStruct
450+
end_borrow %6 : $NonTrivialStruct
451+
end_borrow %4 : $ComplexStruct
452+
destroy_value %2 : $ComplexStruct
453+
%ret = tuple ()
454+
return %ret : $()
455+
}
456+

0 commit comments

Comments
 (0)