Skip to content

Commit 0f58bf6

Browse files
committed
Add tests for generics and fix handling of generics
1 parent c1bed74 commit 0f58bf6

File tree

4 files changed

+107
-31
lines changed

4 files changed

+107
-31
lines changed

lib/SILGen/SILGenDestructor.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,8 @@ void SILGenFunction::destroyClassMember(SILLocation cleanupLoc,
220220
}
221221
}
222222

223-
llvm::SmallSetVector<VarDecl *, 4> findRecursiveLinks(DeclContext *DC,
224-
ClassDecl *cd) {
225-
auto SelfTy = DC->mapTypeIntoContext(cd->getDeclaredInterfaceType());
223+
llvm::SmallSetVector<VarDecl *, 4> findRecursiveLinks(ClassDecl *cd) {
224+
auto SelfTy = cd->getDeclaredInterfaceType();
226225

227226
// Collect all stored properties that would form a recursive structure,
228227
// so we can remove the recursion and prevent the call stack from
@@ -262,7 +261,8 @@ void SILGenFunction::emitRecursiveChainDestruction(
262261

263262
// var iter = self.link
264263
// self.link = nil
265-
auto Ty = getTypeLowering(vd->getInterfaceType()).getLoweredType();
264+
auto Ty = getTypeLowering(F.mapTypeIntoContext(vd->getInterfaceType()))
265+
.getLoweredType();
266266
auto optionalNone = B.createOptionalNone(cleanupLoc, Ty);
267267
SILValue varAddr = B.createRefElementAddr(cleanupLoc, selfValue.getValue(),
268268
vd, Ty.getAddressType());
@@ -375,7 +375,7 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
375375
finishBB);
376376
}
377377

378-
auto recursiveLinks = findRecursiveLinks(F.getDeclContext(), cd);
378+
auto recursiveLinks = findRecursiveLinks(cd);
379379

380380
/// Destroy all members.
381381
{
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
// Non-linearly recursive structures should not get optimized
4+
class Tree {
5+
var left: Tree?
6+
var right: Tree?
7+
}
8+
9+
// CHECK: sil hidden [ossa] @$s16deinit_recursive4TreeCfd : $@convention(method) (@guaranteed Tree) -> @owned Builtin.NativeObject {
10+
// CHECK: // [[SELF:%.*]] "self"
11+
// CHECK: bb0([[SELF]] : @guaranteed $Tree):
12+
// CHECK: [[LEFT:%.*]] = ref_element_addr [[SELF]] : $Tree, #Tree.left
13+
// CHECK: [[LEFT_ACCESS:%.*]] = begin_access [deinit] [static] [[LEFT]] : $*Optional<Tree>
14+
// CHECK: destroy_addr [[LEFT_ACCESS]] : $*Optional<Tree>
15+
// CHECK: end_access [[LEFT_ACCESS]] : $*Optional<Tree>
16+
// CHECK: [[RIGHT:%.*]] = ref_element_addr [[SELF]] : $Tree, #Tree.right
17+
// CHECK: [[RIGHT_ACCESS:%.*]] = begin_access [deinit] [static] [[RIGHT]] : $*Optional<Tree>
18+
// CHECK: destroy_addr [[RIGHT_ACCESS]] : $*Optional<Tree>
19+
// CHECK: end_access [[RIGHT_ACCESS]] : $*Optional<Tree> // id: %9
20+
// CHECK: [[SELF_NATIVE:%.*]] = unchecked_ref_cast [[SELF]] : $Tree to $Builtin.NativeObject
21+
// CHECK: [[SELF_NATIVE_OWNED:%.*]] = unchecked_ownership_conversion [[SELF_NATIVE]] : $Builtin.NativeObject, @guaranteed to @owned
22+
// CHECK: return [[SELF_NATIVE_OWNED]] : $Builtin.NativeObject
23+
// CHECK: } // end sil function '$s16deinit_recursive4TreeCfd'

test/SILGen/deinit_recursive.swift renamed to test/SILGen/deinit_recursive_linear.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,29 +63,3 @@ class Node {
6363
// CHECK: [[SELF_NATIVE_OWNED:%.*]] = unchecked_ownership_conversion [[SELF_NATIVE]] : $Builtin.NativeObject, @guaranteed to @owned
6464
// CHECK: return [[SELF_NATIVE_OWNED]] : $Builtin.NativeObject
6565
// CHECK: } // end sil function '$s16deinit_recursive4NodeCfd'
66-
67-
68-
69-
70-
71-
// Non-linearly recursive structures should not get optimized
72-
class Tree {
73-
var left: Tree?
74-
var right: Tree?
75-
}
76-
77-
// CHECK: sil hidden [ossa] @$s16deinit_recursive4TreeCfd : $@convention(method) (@guaranteed Tree) -> @owned Builtin.NativeObject {
78-
// CHECK: // [[SELF:%.*]] "self"
79-
// CHECK: bb0([[SELF]] : @guaranteed $Tree):
80-
// CHECK: [[LEFT:%.*]] = ref_element_addr [[SELF]] : $Tree, #Tree.left
81-
// CHECK: [[LEFT_ACCESS:%.*]] = begin_access [deinit] [static] [[LEFT]] : $*Optional<Tree>
82-
// CHECK: destroy_addr [[LEFT_ACCESS]] : $*Optional<Tree>
83-
// CHECK: end_access [[LEFT_ACCESS]] : $*Optional<Tree>
84-
// CHECK: [[RIGHT:%.*]] = ref_element_addr [[SELF]] : $Tree, #Tree.right
85-
// CHECK: [[RIGHT_ACCESS:%.*]] = begin_access [deinit] [static] [[RIGHT]] : $*Optional<Tree>
86-
// CHECK: destroy_addr [[RIGHT_ACCESS]] : $*Optional<Tree>
87-
// CHECK: end_access [[RIGHT_ACCESS]] : $*Optional<Tree> // id: %9
88-
// CHECK: [[SELF_NATIVE:%.*]] = unchecked_ref_cast [[SELF]] : $Tree to $Builtin.NativeObject
89-
// CHECK: [[SELF_NATIVE_OWNED:%.*]] = unchecked_ownership_conversion [[SELF_NATIVE]] : $Builtin.NativeObject, @guaranteed to @owned
90-
// CHECK: return [[SELF_NATIVE_OWNED]] : $Builtin.NativeObject
91-
// CHECK: } // end sil function '$s16deinit_recursive4TreeCfd'
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
class Node<A, B> {
4+
var next: Node<A, B>?
5+
}
6+
7+
// CHECK: sil hidden [ossa] @$s31deinit_recursive_linear_generic4NodeCfd : $@convention(method) <A, B> (@guaranteed Node<A, B>) -> @owned Builtin.NativeObject {
8+
// CHECK: [[SELF:%.*]] "self"
9+
// CHECK: bb0([[SELF]] : @guaranteed $Node<A, B>):
10+
// CHECK: [[NIL:%.*]] = enum $Optional<Node<A, B>>, #Optional.none!enumelt
11+
// CHECK: [[SELF_NEXT:%.*]] = ref_element_addr [[SELF]] : $Node<A, B>, #Node.next
12+
// CHECK: [[ITER:%.*]] = alloc_stack $Optional<Node<A, B>>
13+
// CHECK: [[SELF_NEXT_ACCESS:%.*]] = begin_access [modify] [static] [[SELF_NEXT]] : $*Optional<Node<A, B>>
14+
// CHECK: [[SELF_NEXT_COPY:%.*]] = load [copy] [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
15+
// CHECK: store [[NIL]] to [assign] [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
16+
// CHECK: end_access [[SELF_NEXT_ACCESS]] : $*Optional<Node<A, B>>
17+
// CHECK: store [[SELF_NEXT_COPY]] to [init] [[ITER]] : $*Optional<Node<A, B>>
18+
// CHECK: br [[LOOPBB:bb.*]] //
19+
20+
// CHECK: [[LOOPBB]]:
21+
// CHECK: [[ITER_ADDR:%.*]] = load [copy] [[ITER]] : $*Optional<Node<A, B>>
22+
// CHECK: [[ITER_COPY:%.*]] = copy_value [[ITER_ADDR]] : $Optional<Node<A, B>>
23+
// CHECK: [[ITER_COPY_ADDR:%.*]] = alloc_stack $Optional<Node<A, B>>
24+
// CHECK: store [[ITER_COPY]] to [init] [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
25+
// CHECK: destroy_value [[ITER_ADDR]] : $Optional<Node<A, B>>
26+
// CHECK: switch_enum_addr [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>, case #Optional.some!enumelt: [[IS_SOME_BB:bb.*]], case #Optional.none!enumelt: [[IS_NONE_BB:bb[0-9]+]]
27+
28+
// CHECK: [[IS_SOME_BB]]:
29+
// CHECK: destroy_addr [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
30+
// CHECK: dealloc_stack [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
31+
// CHECK: [[IS_UNIQUE:%.*]] = is_unique [[ITER]] : $*Optional<Node<A, B>>
32+
// CHECK: cond_br [[IS_UNIQUE]], [[IS_UNIQUE_BB:bb.*]], [[NOT_UNIQUE_BB:bb[0-9]*]]
33+
34+
// CHECK: [[IS_UNIQUE_BB]]:
35+
// CHECK: [[ITER_ADDR:%.*]] = load [copy] [[ITER]] : $*Optional<Node<A, B>>
36+
// CHECK: [[ITER_BORROW:%.*]] = begin_borrow [[ITER_ADDR]] : $Optional<Node<A, B>>
37+
// CHECK: [[ITER_UNWRAPPED:%.*]] = unchecked_enum_data [[ITER_BORROW]] : $Optional<Node<A, B>>, #Optional.some!enumelt
38+
// CHECK: [[NEXT_ADDR:%.*]] = ref_element_addr [[ITER_UNWRAPPED]] : $Node<A, B>, #Node.next
39+
// CHECK: [[NEXT_ADDR_ACCESS:%.*]] = begin_access [read] [static] [[NEXT_ADDR]] : $*Optional<Node<A, B>>
40+
// CHECK: [[NEXT_COPY:%.*]] = load [copy] [[NEXT_ADDR_ACCESS]] : $*Optional<Node<A, B>>
41+
// CHECK: end_access [[NEXT_ADDR_ACCESS]] : $*Optional<Node<A, B>>
42+
// CHECK: store [[NEXT_COPY]] to [assign] [[ITER]] : $*Optional<Node<A, B>>
43+
// CHECK: end_borrow [[ITER_BORROW]] : $Optional<Node<A, B>>
44+
// CHECK: destroy_value [[ITER_ADDR]] : $Optional<Node<A, B>>
45+
// CHECK: br [[LOOPBB]]
46+
47+
// CHECK: [[NOT_UNIQUE_BB]]:
48+
// CHECK: br bb6
49+
50+
// CHECK: [[IS_NONE_BB]]:
51+
// CHECK: dealloc_stack [[ITER_COPY_ADDR]] : $*Optional<Node<A, B>>
52+
// CHECK: br [[CLEAN_BB:bb[0-9]+]]
53+
54+
// CHECK: [[CLEAN_BB]]:
55+
// CHECK: destroy_addr [[ITER]] : $*Optional<Node<A, B>>
56+
// CHECK: dealloc_stack [[ITER]] : $*Optional<Node<A, B>>
57+
// CHECK: [[SELF_NATIVE:%.*]] = unchecked_ref_cast [[SELF]] : $Node<A, B> to $Builtin.NativeObject
58+
// CHECK: [[SELF_NATIVE_OWNED:%.*]] = unchecked_ownership_conversion [[SELF_NATIVE]] : $Builtin.NativeObject, @guaranteed to @owned
59+
// CHECK: return [[SELF_NATIVE_OWNED]] : $Builtin.NativeObject
60+
// CHECK: } // end sil function '$s31deinit_recursive_linear_generic4NodeCfd'
61+
62+
63+
// Types of `self` and `next` don't match, so this should not be optimized
64+
class Node2<A, B> {
65+
var next: Node2<Int, (A, B)>?
66+
}
67+
68+
// CHECK: sil hidden [ossa] @$s31deinit_recursive_linear_generic5Node2Cfd : $@convention(method) <A, B> (@guaranteed Node2<A, B>) -> @owned Builtin.NativeObject {
69+
// CHECK: [[SELF:%.*]] "self"
70+
// CHECK: bb0([[SELF]] : @guaranteed $Node2<A, B>):
71+
// CHECK: debug_value [[SELF]] : $Node2<A, B>, let, name "self", argno 1, implicit
72+
// CHECK: [[NEXT_ADDR:%.*]] = ref_element_addr [[SELF]] : $Node2<A, B>, #Node2.next
73+
// CHECK: [[NEXT_ACCESS:%.*]] = begin_access [deinit] [static] [[NEXT_ADDR]] : $*Optional<Node2<Int, (A, B)>>
74+
// CHECK: destroy_addr [[NEXT_ACCESS]] : $*Optional<Node2<Int, (A, B)>>
75+
// CHECK: end_access [[NEXT_ACCESS]] : $*Optional<Node2<Int, (A, B)>>
76+
// CHECK: [[SELF_NATIVE:%.*]] = unchecked_ref_cast [[SELF]] : $Node2<A, B> to $Builtin.NativeObject
77+
// CHECK: [[SELF_OWNED:%.*]] = unchecked_ownership_conversion [[SELF_NATIVE]] : $Builtin.NativeObject, @guaranteed to @owned
78+
// CHECK: return [[SELF_OWNED]] : $Builtin.NativeObject
79+
// CHECK: } // end sil function '$s31deinit_recursive_linear_generic5Node2Cfd'

0 commit comments

Comments
 (0)