Skip to content

Commit 54e0a54

Browse files
committed
MemoryLifetime: support checked_cast_addr_br
1 parent 85a5826 commit 54e0a54

File tree

7 files changed

+161
-26
lines changed

7 files changed

+161
-26
lines changed

include/swift/SIL/MemoryLifetime.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,31 @@ class MemoryLocations {
236236

237237
/// Sets the location bits os \p addr in \p bits, if \p addr is associated
238238
/// with a location.
239-
void setBits(Bits &bits, SILValue addr) {
239+
void setBits(Bits &bits, SILValue addr) const {
240240
if (auto *loc = getLocation(addr))
241241
bits |= loc->subLocations;
242242
}
243243

244244
/// Clears the location bits os \p addr in \p bits, if \p addr is associated
245245
/// with a location.
246-
void clearBits(Bits &bits, SILValue addr) {
246+
void clearBits(Bits &bits, SILValue addr) const {
247247
if (auto *loc = getLocation(addr))
248248
bits.reset(loc->subLocations);
249249
}
250+
251+
void genBits(Bits &genSet, Bits &killSet, SILValue addr) const {
252+
if (auto *loc = getLocation(addr)) {
253+
killSet.reset(loc->subLocations);
254+
genSet |= loc->subLocations;
255+
}
256+
}
257+
258+
void killBits(Bits &genSet, Bits &killSet, SILValue addr) const {
259+
if (auto *loc = getLocation(addr)) {
260+
killSet |= loc->subLocations;
261+
genSet.reset(loc->subLocations);
262+
}
263+
}
250264

251265
/// Analyzes all locations in a function.
252266
///
@@ -368,17 +382,11 @@ class MemoryDataflow {
368382
// Utility functions for setting and clearing gen- and kill-bits.
369383

370384
void genBits(SILValue addr, const MemoryLocations &locs) {
371-
if (auto *loc = locs.getLocation(addr)) {
372-
killSet.reset(loc->subLocations);
373-
genSet |= loc->subLocations;
374-
}
385+
locs.genBits(genSet, killSet, addr);
375386
}
376387

377388
void killBits(SILValue addr, const MemoryLocations &locs) {
378-
if (auto *loc = locs.getLocation(addr)) {
379-
genSet.reset(loc->subLocations);
380-
killSet |= loc->subLocations;
381-
}
389+
locs.killBits(genSet, killSet, addr);
382390
}
383391

384392
bool exitReachable() const {

lib/SIL/Verifier/MemoryLifetime.cpp

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ bool MemoryLocations::analyzeLocationUsesRecursively(SILValue V, unsigned locIdx
356356
case SILInstructionKind::EndAccessInst:
357357
case SILInstructionKind::LoadBorrowInst:
358358
case SILInstructionKind::DestroyAddrInst:
359+
case SILInstructionKind::CheckedCastAddrBranchInst:
359360
case SILInstructionKind::PartialApplyInst:
360361
case SILInstructionKind::ApplyInst:
361362
case SILInstructionKind::TryApplyInst:
@@ -665,7 +666,7 @@ class MemoryLifetimeVerifier {
665666
/// in \p block.
666667
/// Example: @out results of try_apply. They are only valid in the
667668
/// normal-block, but not in the throw-block.
668-
void setBitsOfPredecessor(Bits &bits, SILBasicBlock *block);
669+
void setBitsOfPredecessor(Bits &genSet, Bits &killSet, SILBasicBlock *block);
669670

670671
/// Initializes the data flow bits sets in the block states for all blocks.
671672
void initDataflow(MemoryDataflow &dataFlow);
@@ -867,7 +868,7 @@ void MemoryLifetimeVerifier::initDataflowInBlock(SILBasicBlock *block,
867868
BlockState &state) {
868869
// Initialize the genSet with special cases, like the @out results of an
869870
// try_apply in the predecessor block.
870-
setBitsOfPredecessor(state.genSet, block);
871+
setBitsOfPredecessor(state.genSet, state.killSet, block);
871872

872873
for (SILInstruction &I : *block) {
873874
switch (I.getKind()) {
@@ -939,25 +940,42 @@ void MemoryLifetimeVerifier::initDataflowInBlock(SILBasicBlock *block,
939940
}
940941
}
941942

942-
void MemoryLifetimeVerifier::setBitsOfPredecessor(Bits &bits,
943+
void MemoryLifetimeVerifier::setBitsOfPredecessor(Bits &getSet, Bits &killSet,
943944
SILBasicBlock *block) {
944945
SILBasicBlock *pred = block->getSinglePredecessorBlock();
945946
if (!pred)
946947
return;
947948

948-
auto *TAI = dyn_cast<TryApplyInst>(pred->getTerminator());
949-
950-
// @out results of try_apply are only valid in the normal-block, but not in
951-
// the throw-block.
952-
if (!TAI || TAI->getNormalBB() != block)
953-
return;
949+
TermInst *term = pred->getTerminator();
950+
if (auto *tai = dyn_cast<TryApplyInst>(term)) {
951+
// @out results of try_apply are only valid in the normal-block, but not in
952+
// the throw-block.
953+
if (tai->getNormalBB() != block)
954+
return;
954955

955-
FullApplySite FAS(TAI);
956-
for (Operand &op : TAI->getAllOperands()) {
957-
if (FAS.isArgumentOperand(op) &&
958-
FAS.getArgumentConvention(op) == SILArgumentConvention::Indirect_Out) {
959-
locations.setBits(bits, op.get());
956+
FullApplySite FAS(tai);
957+
for (Operand &op : tai->getAllOperands()) {
958+
if (FAS.isArgumentOperand(op) &&
959+
FAS.getArgumentConvention(op) == SILArgumentConvention::Indirect_Out) {
960+
locations.genBits(getSet, killSet, op.get());
961+
}
962+
}
963+
} else if (auto *castInst = dyn_cast<CheckedCastAddrBranchInst>(term)) {
964+
switch (castInst->getConsumptionKind()) {
965+
case CastConsumptionKind::TakeAlways:
966+
locations.killBits(getSet, killSet, castInst->getSrc());
967+
break;
968+
case CastConsumptionKind::TakeOnSuccess:
969+
if (castInst->getSuccessBB() == block)
970+
locations.killBits(getSet, killSet, castInst->getSrc());
971+
break;
972+
case CastConsumptionKind::CopyOnSuccess:
973+
break;
974+
case CastConsumptionKind::BorrowAlways:
975+
llvm_unreachable("checked_cast_addr_br cannot have BorrowAlways");
960976
}
977+
if (castInst->getSuccessBB() == block)
978+
locations.genBits(getSet, killSet, castInst->getDest());
961979
}
962980
}
963981

@@ -1050,7 +1068,7 @@ void MemoryLifetimeVerifier::checkFunction(MemoryDataflow &dataFlow) {
10501068
}
10511069

10521070
void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
1053-
setBitsOfPredecessor(bits, block);
1071+
setBitsOfPredecessor(bits, bits, block);
10541072
const Bits &nonTrivialLocations = locations.getNonTrivialLocations();
10551073

10561074
for (SILInstruction &I : *block) {
@@ -1153,6 +1171,12 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
11531171
requireBitsSet(bits, orig, &I);
11541172
break;
11551173
}
1174+
case SILInstructionKind::CheckedCastAddrBranchInst: {
1175+
auto *castInst = cast<CheckedCastAddrBranchInst>(&I);
1176+
requireBitsSet(bits, castInst->getSrc(), &I);
1177+
requireBitsClear(bits & nonTrivialLocations, castInst->getDest(), &I);
1178+
break;
1179+
}
11561180
case SILInstructionKind::PartialApplyInst:
11571181
case SILInstructionKind::ApplyInst:
11581182
case SILInstructionKind::TryApplyInst: {

lib/SILOptimizer/Transforms/DestroyHoisting.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ void DestroyHoisting::getUsedLocationsOfInst(Bits &bits, SILInstruction *I) {
353353
case SILInstructionKind::StoreBorrowInst:
354354
case SILInstructionKind::CopyAddrInst:
355355
case SILInstructionKind::InjectEnumAddrInst:
356+
case SILInstructionKind::CheckedCastAddrBranchInst:
356357
case SILInstructionKind::PartialApplyInst:
357358
case SILInstructionKind::ApplyInst:
358359
case SILInstructionKind::TryApplyInst:

test/SIL/memory_lifetime.sil

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,51 @@ bb0(%0 : @guaranteed $T):
493493
return %res : $()
494494
}
495495

496+
sil [ossa] @test_cast_br_take_always : $@convention(thin) <U, V> (@in U) -> () {
497+
bb0(%0 : $*U):
498+
%s = alloc_stack $V
499+
checked_cast_addr_br take_always U in %0 : $*U to V in %s : $*V, bb1, bb2
500+
bb1:
501+
destroy_addr %s : $*V
502+
br bb3
503+
bb2:
504+
br bb3
505+
bb3:
506+
dealloc_stack %s : $*V
507+
%res = tuple ()
508+
return %res : $()
509+
}
510+
511+
sil [ossa] @test_cast_br_take_on_success : $@convention(thin) <U, V> (@in U) -> () {
512+
bb0(%0 : $*U):
513+
%s = alloc_stack $V
514+
checked_cast_addr_br take_on_success U in %0 : $*U to V in %s : $*V, bb1, bb2
515+
bb1:
516+
destroy_addr %s : $*V
517+
br bb3
518+
bb2:
519+
destroy_addr %0 : $*U
520+
br bb3
521+
bb3:
522+
dealloc_stack %s : $*V
523+
%res = tuple ()
524+
return %res : $()
525+
}
526+
527+
sil [ossa] @test_cast_br_copy_on_success : $@convention(thin) <U, V> (@in U) -> () {
528+
bb0(%0 : $*U):
529+
%s = alloc_stack $V
530+
checked_cast_addr_br copy_on_success U in %0 : $*U to V in %s : $*V, bb1, bb2
531+
bb1:
532+
destroy_addr %0 : $*U
533+
destroy_addr %s : $*V
534+
br bb3
535+
bb2:
536+
destroy_addr %0 : $*U
537+
br bb3
538+
bb3:
539+
dealloc_stack %s : $*V
540+
%res = tuple ()
541+
return %res : $()
542+
}
543+

test/SIL/memory_lifetime_failures.sil

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,53 @@ bb0(%0 : @guaranteed $Optional<T>):
350350
return %res : $()
351351
}
352352

353+
// CHECK: SIL memory lifetime failure in @test_cast_br_take_always: memory is not initialized, but should
354+
sil [ossa] @test_cast_br_take_always : $@convention(thin) <U, V> (@in U) -> () {
355+
bb0(%0 : $*U):
356+
%s = alloc_stack $V
357+
checked_cast_addr_br take_always U in %0 : $*U to V in %s : $*V, bb1, bb2
358+
bb1:
359+
destroy_addr %s : $*V
360+
br bb3
361+
bb2:
362+
destroy_addr %0 : $*U
363+
br bb3
364+
bb3:
365+
dealloc_stack %s : $*V
366+
%res = tuple ()
367+
return %res : $()
368+
}
369+
370+
// CHECK: SIL memory lifetime failure in @test_cast_br_take_on_success: lifetime mismatch in predecessors
371+
sil [ossa] @test_cast_br_take_on_success : $@convention(thin) <U, V> (@in U) -> () {
372+
bb0(%0 : $*U):
373+
%s = alloc_stack $V
374+
checked_cast_addr_br take_on_success U in %0 : $*U to V in %s : $*V, bb1, bb2
375+
bb1:
376+
destroy_addr %s : $*V
377+
br bb3
378+
bb2:
379+
br bb3
380+
bb3:
381+
dealloc_stack %s : $*V
382+
%res = tuple ()
383+
return %res : $()
384+
}
385+
386+
// CHECK: SIL memory lifetime failure in @test_cast_br_copy_on_success: lifetime mismatch in predecessors
387+
sil [ossa] @test_cast_br_copy_on_success : $@convention(thin) <U, V> (@in U) -> () {
388+
bb0(%0 : $*U):
389+
%s = alloc_stack $V
390+
checked_cast_addr_br copy_on_success U in %0 : $*U to V in %s : $*V, bb1, bb2
391+
bb1:
392+
destroy_addr %s : $*V
393+
br bb3
394+
bb2:
395+
destroy_addr %0 : $*U
396+
br bb3
397+
bb3:
398+
dealloc_stack %s : $*V
399+
%res = tuple ()
400+
return %res : $()
401+
}
402+

test/SIL/ownership-verifier/load_borrow_invalidation_test.sil

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,13 @@ bb0(%0 : $*Builtin.NativeObject):
301301
checked_cast_addr_br take_always Builtin.NativeObject in %0 : $*Builtin.NativeObject to Builtin.NativeObject in %stack0 : $*Builtin.NativeObject, bb1, bb2
302302

303303
bb1:
304+
destroy_addr %stack0 : $*Builtin.NativeObject
304305
br bb3
305306

306307
bb2:
307308
br bb3
308309

309310
bb3:
310-
destroy_addr %stack0 : $*Builtin.NativeObject
311311
dealloc_stack %stack0 : $*Builtin.NativeObject
312312
%9999 = tuple()
313313
return %9999 : $()
@@ -326,6 +326,7 @@ bb1:
326326
br bb3
327327

328328
bb2:
329+
destroy_addr %0 : $*Builtin.NativeObject
329330
br bb3
330331

331332
bb3:

test/SILOptimizer/sil_combine_enum_addr_ossa.sil

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ bb1:
115115

116116
bb2:
117117
dealloc_stack %5 : $*Int
118+
destroy_addr %3 : $*Optional<CustomStringConvertible>
118119
dealloc_stack %3 : $*Optional<CustomStringConvertible>
119120
%12 = integer_literal $Builtin.Int1, -1
120121
%13 = integer_literal $Builtin.Int1, 0
@@ -171,6 +172,7 @@ bb1:
171172

172173
bb2:
173174
dealloc_stack %5 : $*A
175+
destroy_addr %3 : $*Optional<CustomStringConvertible>
174176
dealloc_stack %3 : $*Optional<CustomStringConvertible>
175177
%12 = integer_literal $Builtin.Int1, -1
176178
%13 = integer_literal $Builtin.Int1, 0
@@ -257,6 +259,7 @@ bb1:
257259

258260
bb2:
259261
dealloc_stack %5 : $*D
262+
destroy_addr %3 : $*Optional<CustomStringConvertible>
260263
dealloc_stack %3 : $*Optional<CustomStringConvertible>
261264
%12 = integer_literal $Builtin.Int1, -1
262265
%13 = integer_literal $Builtin.Int1, 0

0 commit comments

Comments
 (0)