Skip to content

Commit b73285d

Browse files
committed
MemoryLifetime: support unchecked_ref_cast_addr and unconditional_checked_cast_addr instructions
1 parent ccf44f6 commit b73285d

File tree

4 files changed

+87
-0
lines changed

4 files changed

+87
-0
lines changed

lib/SIL/Verifier/MemoryLifetime.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ bool MemoryLocations::analyzeLocationUsesRecursively(SILValue V, unsigned locIdx
357357
case SILInstructionKind::LoadBorrowInst:
358358
case SILInstructionKind::DestroyAddrInst:
359359
case SILInstructionKind::CheckedCastAddrBranchInst:
360+
case SILInstructionKind::UncheckedRefCastAddrInst:
361+
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
360362
case SILInstructionKind::PartialApplyInst:
361363
case SILInstructionKind::ApplyInst:
362364
case SILInstructionKind::TryApplyInst:
@@ -914,6 +916,14 @@ void MemoryLifetimeVerifier::initDataflowInBlock(SILBasicBlock *block,
914916
case SILInstructionKind::DeallocStackInst:
915917
state.killBits(I.getOperand(0), locations);
916918
break;
919+
case SILInstructionKind::UncheckedRefCastAddrInst:
920+
case SILInstructionKind::UnconditionalCheckedCastAddrInst: {
921+
SILValue src = I.getOperand(CopyLikeInstruction::Src);
922+
SILValue dest = I.getOperand(CopyLikeInstruction::Dest);
923+
state.killBits(src, locations);
924+
state.genBits(dest, locations);
925+
break;
926+
}
917927
case SILInstructionKind::PartialApplyInst:
918928
case SILInstructionKind::ApplyInst:
919929
case SILInstructionKind::TryApplyInst: {
@@ -1171,6 +1181,17 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
11711181
requireBitsSet(bits, orig, &I);
11721182
break;
11731183
}
1184+
case SILInstructionKind::UncheckedRefCastAddrInst:
1185+
case SILInstructionKind::UnconditionalCheckedCastAddrInst: {
1186+
SILValue src = I.getOperand(CopyLikeInstruction::Src);
1187+
SILValue dest = I.getOperand(CopyLikeInstruction::Dest);
1188+
requireBitsSet(bits, src, &I);
1189+
locations.clearBits(bits, src);
1190+
requireBitsClear(bits & nonTrivialLocations, dest, &I);
1191+
locations.setBits(bits, dest);
1192+
requireNoStoreBorrowLocation(dest, &I);
1193+
break;
1194+
}
11741195
case SILInstructionKind::CheckedCastAddrBranchInst: {
11751196
auto *castInst = cast<CheckedCastAddrBranchInst>(&I);
11761197
requireBitsSet(bits, castInst->getSrc(), &I);

lib/SILOptimizer/Transforms/DestroyHoisting.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ void DestroyHoisting::getUsedLocationsOfInst(Bits &bits, SILInstruction *I) {
353353
case SILInstructionKind::StoreBorrowInst:
354354
case SILInstructionKind::CopyAddrInst:
355355
case SILInstructionKind::InjectEnumAddrInst:
356+
case SILInstructionKind::UncheckedRefCastAddrInst:
357+
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
356358
case SILInstructionKind::CheckedCastAddrBranchInst:
357359
case SILInstructionKind::PartialApplyInst:
358360
case SILInstructionKind::ApplyInst:

test/SIL/memory_lifetime.sil

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,22 @@ bb3:
541541
return %res : $()
542542
}
543543

544+
sil [ossa] @test_unconditional_checked_cast : $@convention(thin) <U, V> (@in U) -> () {
545+
bb0(%0 : $*U):
546+
%s = alloc_stack $V
547+
unconditional_checked_cast_addr U in %0 : $*U to V in %s : $*V
548+
destroy_addr %s : $*V
549+
dealloc_stack %s : $*V
550+
%5 = tuple ()
551+
return %5 : $()
552+
}
553+
554+
sil [ossa] @test_unchecked_ref_cast : $@convention(thin) <U : AnyObject, V : AnyObject> (@in U) -> () {
555+
bb0(%0 : $*U):
556+
%s = alloc_stack $V
557+
unchecked_ref_cast_addr U in %0 : $*U to V in %s : $*V
558+
destroy_addr %s : $*V
559+
dealloc_stack %s : $*V
560+
%5 = tuple ()
561+
return %5 : $()
562+
}

test/SIL/memory_lifetime_failures.sil

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,48 @@ bb3:
400400
return %res : $()
401401
}
402402

403+
// CHECK: SIL memory lifetime failure in @test_unconditional_checked_cast_1: memory is initialized, but shouldn't
404+
sil [ossa] @test_unconditional_checked_cast_1 : $@convention(thin) <U, V> (@in U) -> () {
405+
bb0(%0 : $*U):
406+
%s = alloc_stack $V
407+
unconditional_checked_cast_addr U in %0 : $*U to V in %s : $*V
408+
dealloc_stack %s : $*V
409+
%5 = tuple ()
410+
return %5 : $()
411+
}
412+
413+
// CHECK: SIL memory lifetime failure in @test_unconditional_checked_cast_2: memory is not initialized, but should
414+
sil [ossa] @test_unconditional_checked_cast_2 : $@convention(thin) <U, V> (@in_guaranteed U) -> () {
415+
bb0(%0 : $*U):
416+
%u = alloc_stack $U
417+
%s = alloc_stack $V
418+
unconditional_checked_cast_addr U in %u : $*U to V in %s : $*V
419+
destroy_addr %s : $*V
420+
dealloc_stack %s : $*V
421+
dealloc_stack %u : $*U
422+
%5 = tuple ()
423+
return %5 : $()
424+
}
425+
426+
// CHECK: SIL memory lifetime failure in @test_unchecked_ref_cast_1: memory is initialized, but shouldn't
427+
sil [ossa] @test_unchecked_ref_cast_1 : $@convention(thin) <U : AnyObject, V : AnyObject> (@in U) -> () {
428+
bb0(%0 : $*U):
429+
%s = alloc_stack $V
430+
unchecked_ref_cast_addr U in %0 : $*U to V in %s : $*V
431+
dealloc_stack %s : $*V
432+
%5 = tuple ()
433+
return %5 : $()
434+
}
435+
436+
// CHECK: SIL memory lifetime failure in @test_unchecked_ref_cast_2: memory is not initialized, but should
437+
sil [ossa] @test_unchecked_ref_cast_2 : $@convention(thin) <U : AnyObject, V : AnyObject> (@in_guaranteed U) -> () {
438+
bb0(%0 : $*U):
439+
%u = alloc_stack $U
440+
%s = alloc_stack $V
441+
unchecked_ref_cast_addr U in %u : $*U to V in %s : $*V
442+
destroy_addr %s : $*V
443+
dealloc_stack %s : $*V
444+
dealloc_stack %u : $*U
445+
%5 = tuple ()
446+
return %5 : $()
447+
}

0 commit comments

Comments
 (0)