Skip to content

Commit c6e3f51

Browse files
committed
EscapeInfo: handle unchecked_addr_cast
It's dangerous to continue walking over an `unchecked_addr_cast` which casts between two different types. We can only do this if the result is known to be the end of the walk, i.e. the cast result is not used in a relevant way.
1 parent 1440ae7 commit c6e3f51

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,26 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
558558
case is DeallocStackInst, is InjectEnumAddrInst, is FixLifetimeInst, is EndBorrowInst, is EndAccessInst,
559559
is IsUniqueInst, is DebugValueInst:
560560
return .continueWalk
561+
case let uac as UncheckedAddrCastInst:
562+
if uac.type != uac.fromAddress.type {
563+
// It's dangerous to continue walking over an `unchecked_addr_cast` which casts between two different types.
564+
// We can only do this if the result is known to be the end of the walk, i.e. the cast result is not used
565+
// in a relevant way.
566+
for uacUse in uac.uses {
567+
// Following instructions turned out to appear in code coming from the stdlib.
568+
switch uacUse.instruction {
569+
case is IsUniqueInst:
570+
break
571+
case is LoadInst, is LoadBorrowInst:
572+
if followLoads(at: path) {
573+
return .abortWalk
574+
}
575+
default:
576+
return .abortWalk
577+
}
578+
}
579+
}
580+
return walkDownUses(ofAddress: uac, path: path)
561581
default:
562582
return isEscaping
563583
}

test/SILOptimizer/addr_escape_info.sil

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,3 +811,37 @@ bb0(%0 : @owned $X):
811811
return %4 : $()
812812
}
813813

814+
// CHECK-LABEL: Address escape information for test_unchecked_addr_cast:
815+
// CHECK: value: %1 = alloc_stack $X
816+
// CHECK-NEXT: End function test_unchecked_addr_cast
817+
sil [ossa] @test_unchecked_addr_cast : $@convention(thin) (@owned X) -> @owned XandIntClass {
818+
bb0(%0 : @owned $X):
819+
%1 = alloc_stack $X
820+
store %0 to [init] %1 : $*X
821+
fix_lifetime %1 : $*X
822+
%4 = unchecked_addr_cast %1 : $*X to $*XandIntClass
823+
%5 = is_unique %4 : $*XandIntClass
824+
%6 = load_borrow %4 : $*XandIntClass
825+
end_borrow %6 : $XandIntClass
826+
%8 = load [take] %4 : $*XandIntClass
827+
dealloc_stack %1 : $*X
828+
return %8 : $XandIntClass
829+
}
830+
831+
// CHECK-LABEL: Address escape information for test_unchecked_addr_cast_escaping:
832+
// CHECK: value: %1 = alloc_stack $X
833+
// CHECK-NEXT: ==> %6 = apply %5(%4) : $@convention(thin) (@inout X) -> ()
834+
// CHECK-NEXT: End function test_unchecked_addr_cast_escaping
835+
sil [ossa] @test_unchecked_addr_cast_escaping : $@convention(thin) (@owned XandIntClass) -> () {
836+
bb0(%0 : @owned $XandIntClass):
837+
%1 = alloc_stack $XandIntClass
838+
store %0 to [init] %1 : $*XandIntClass
839+
fix_lifetime %1 : $*XandIntClass
840+
%4 = unchecked_addr_cast %1 : $*XandIntClass to $*X
841+
%5 = function_ref @inout_class_argument : $@convention(thin) (@inout X) -> ()
842+
%6 = apply %5(%4) : $@convention(thin) (@inout X) -> ()
843+
dealloc_stack %1 : $*XandIntClass
844+
%8 = tuple ()
845+
return %8 : $()
846+
}
847+

0 commit comments

Comments
 (0)