Skip to content

Commit 70ba193

Browse files
committed
SIL: handle drop_deinit in WalkUtils
Also, handle some other missing instructions in the AddressDefUseWalker, which are visited in the AddressUseDefWalker. This enables various other optimizations, like copy elimination, in the presence of `drop_deinit`. rdar://152307747
1 parent 765204d commit 70ba193

File tree

4 files changed

+67
-15
lines changed

4 files changed

+67
-15
lines changed

SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,12 @@ extension AddressDefUseWalker {
537537
return walkDownUses(ofAddress: ia, path: subPath.push(.anyIndexedElement, index: 0))
538538
}
539539
return walkDownUses(ofAddress: ia, path: path)
540-
case let mmc as MarkUnresolvedNonCopyableValueInst:
541-
return walkDownUses(ofAddress: mmc, path: path)
540+
case is MarkUninitializedInst,
541+
is MoveOnlyWrapperToCopyableAddrInst,
542+
is CopyableToMoveOnlyWrapperAddrInst,
543+
is MarkUnresolvedNonCopyableValueInst,
544+
is DropDeinitInst:
545+
return walkDownUses(ofAddress: instruction as! SingleValueInstruction, path: path)
542546
case let ba as BeginAccessInst:
543547
// Don't treat `end_access` as leaf-use. Just ignore it.
544548
return walkDownNonEndAccessUses(of: ba, path: path)
@@ -828,18 +832,19 @@ extension AddressUseDefWalker {
828832
return walkUp(address: uteda.operand.value, path: path.push(.enumCase, index: uteda.caseIndex))
829833
case is InitExistentialAddrInst, is OpenExistentialAddrInst:
830834
return walkUp(address: (def as! Instruction).operands[0].value, path: path.push(.existential, index: 0))
831-
case is BeginAccessInst, is MarkUnresolvedNonCopyableValueInst:
832-
return walkUp(address: (def as! Instruction).operands[0].value, path: path)
833835
case let ia as IndexAddrInst:
834836
if let idx = ia.constantIndex {
835837
return walkUp(address: ia.base, path: path.push(.indexedElement, index: idx))
836838
} else {
837839
return walkUp(address: ia.base, path: path.push(.anyIndexedElement, index: 0))
838840
}
839-
case is MarkDependenceInst, is MarkUninitializedInst:
840-
return walkUp(address: (def as! Instruction).operands[0].value, path: path)
841-
case is MoveOnlyWrapperToCopyableAddrInst,
842-
is CopyableToMoveOnlyWrapperAddrInst:
841+
case is BeginAccessInst,
842+
is MarkDependenceInst,
843+
is MarkUninitializedInst,
844+
is MoveOnlyWrapperToCopyableAddrInst,
845+
is CopyableToMoveOnlyWrapperAddrInst,
846+
is MarkUnresolvedNonCopyableValueInst,
847+
is DropDeinitInst:
843848
return walkUp(address: (def as! Instruction).operands[0].value, path: path)
844849
default:
845850
return rootDef(address: def, path: path)

test/SILOptimizer/addr_escape_info.sil

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ class X {
2323
@_hasStorage var s: Str
2424
}
2525

26+
struct NonCopyable: ~Copyable {
27+
var a: Int
28+
29+
deinit
30+
}
31+
2632
class D: X {}
2733

2834
struct Container {
@@ -52,6 +58,7 @@ struct NE : ~Escapable {}
5258

5359
sil @no_arguments : $@convention(thin) () -> ()
5460
sil @indirect_argument : $@convention(thin) (@in Int) -> ()
61+
sil @consume_nc : $@convention(thin) (@in NonCopyable) -> ()
5562
sil @indirect_struct_argument : $@convention(thin) (@in Str) -> ()
5663
sil @direct_argument : $@convention(thin) (Int) -> ()
5764
sil @class_argument : $@convention(thin) (@guaranteed X) -> ()
@@ -870,7 +877,7 @@ bb2(%17 : $Error):
870877
}
871878

872879
// CHECK-LABEL: Address escape information for test_store_borrow:
873-
// CHECK: value: %2 = store_borrow %0 to %1 : $*X // users: %4, %3
880+
// CHECK: value: %2 = store_borrow %0 to %1 : $*X
874881
// CHECK-NEXT: End function test_store_borrow
875882
sil [ossa] @test_store_borrow : $@convention(thin) (@guaranteed X) -> () {
876883
bb0(%0 : @guaranteed $X):
@@ -883,6 +890,26 @@ bb0(%0 : @guaranteed $X):
883890
return %3 : $()
884891
}
885892

893+
// CHECK-LABEL: Address escape information for test_drop_deinit:
894+
// CHECK: value: %1 = alloc_stack $NonCopyable
895+
// CHECK-NEXT: - %6 = apply %5() : $@convention(thin) () -> ()
896+
// CHECK-NEXT: ==> %8 = apply %7(%3) : $@convention(thin) (@in NonCopyable) -> ()
897+
// CHECK-NEXT: End function test_drop_deinit
898+
sil [ossa] @test_drop_deinit : $@convention(thin) (@owned NonCopyable) -> () {
899+
bb0(%0 : @owned $NonCopyable):
900+
%1 = alloc_stack $NonCopyable
901+
store %0 to [init] %1
902+
%3 = drop_deinit %1
903+
fix_lifetime %1
904+
%5 = function_ref @no_arguments : $@convention(thin) () -> ()
905+
%6 = apply %5() : $@convention(thin) () -> ()
906+
%7 = function_ref @consume_nc : $@convention(thin) (@in NonCopyable) -> ()
907+
%8 = apply %7(%3) : $@convention(thin) (@in NonCopyable) -> ()
908+
dealloc_stack %1
909+
%10 = tuple ()
910+
return %10 : $()
911+
}
912+
886913
// CHECK-LABEL: Address escape information for noescape_via_independent_addressable:
887914
// CHECK: pair 0 - 1
888915
// CHECK-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(thin) (@in_guaranteed Addressable) -> Builtin.RawPointer
@@ -956,3 +983,4 @@ bb0(%0 : $Int):
956983
%9 = tuple ()
957984
return %9 : $()
958985
}
986+

test/SILOptimizer/lifetime_dependence/scope_fixup.sil

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -404,15 +404,14 @@ bb0:
404404
// Test that initializing LifetimeDependence.Scope from an unidentified enclosing access scope does not
405405
// unwrap nil.
406406
//
407-
// TODO: the mark_dependence should redirect to the drop_deinit, not the struct_element_addr, but AccessBase does not
408-
// currently preserve the address of an unidentified base.
409-
//
410407
// CHECK-LABEL: sil hidden [ossa] @testUnidentified : $@convention(method) (@owned B) -> () {
411-
// CHECK: [[DD:%.*]] = drop_deinit
408+
// CHECK: [[AS:%.*]] = alloc_stack $B
409+
// CHECK: [[MU:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[AS]]
410+
// CHECK: [[DD:%.*]] = drop_deinit [[MU]]
412411
// CHECK: [[SE:%.*]] = struct_element_addr [[DD]], #B.ne
413412
// CHECK: [[LB:%.*]] = load_borrow
414413
// CHECK: apply %{{.*}} : $@convention(thin) (@guaranteed NE) -> UnsafePointer<A>
415-
// CHECK: mark_dependence [unresolved] %{{.*}} on [[SE]]
414+
// CHECK: mark_dependence [unresolved] %{{.*}} on [[AS]]
416415
// CHECK-LABEL: } // end sil function 'testUnidentified'
417416
sil hidden [ossa] @testUnidentified : $@convention(method) (@owned B) -> () {
418417
bb0(%0 : @owned $B):

test/SILOptimizer/optimal_arc.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -module-name test -O -emit-sil -O -primary-file %s | %FileCheck %s
1+
// RUN: %target-swift-frontend -module-name test -O -emit-sil -primary-file %s | %FileCheck %s
22

33
// REQUIRES: optimized_stdlib,swift_stdlib_no_asserts
44

@@ -50,5 +50,25 @@ struct TestCollection: RandomAccessCollection, RangeReplaceableCollection {
5050
}
5151
}
5252

53+
class C {
54+
func foo() {}
55+
}
56+
57+
struct S: ~Copyable {
58+
var c: C
59+
60+
// Check that there is only a single release in the deinit.
61+
62+
// CHECK-LABEL: sil hidden @$s4test1SVfD :
63+
// CHECK-NOT: retain
64+
// CHECK-NOT: release
65+
// CHECK: apply
66+
// CHECK: release
67+
// CHECK-NOT: release
68+
// CHECK: } // end sil function '$s4test1SVfD'
69+
deinit {
70+
c.foo()
71+
}
72+
}
5373

5474

0 commit comments

Comments
 (0)