Skip to content

Commit dbb3ba7

Browse files
committed
[silgen] Change silgen pattern to use destructure_tuple instead of borrow + tuple_extract + copy.
rdar://29791263
1 parent 70a6b35 commit dbb3ba7

File tree

2 files changed

+108
-23
lines changed

2 files changed

+108
-23
lines changed

Diff for: lib/SILGen/SILGenPattern.cpp

+8-23
Original file line numberDiff line numberDiff line change
@@ -1394,33 +1394,18 @@ void PatternMatchEmission::emitTupleDispatchWithOwnership(
13941394
}
13951395

13961396
auto firstPat = rows[0].Pattern;
1397-
auto sourceType = cast<TupleType>(firstPat->getType()->getCanonicalType());
13981397
SILLocation loc = firstPat;
13991398

1400-
// Final consumption here will be either CopyOnSuccess or AlwaysTake. Since we
1401-
// do not have a take operation, we treat it as copy on success always.
1402-
//
1403-
// Once we get a take operation, we should consider allowing for the value to
1404-
// be taken at this point.
1405-
ManagedValue v = src.getFinalManagedValue().borrow(SGF, loc);
1406-
SmallVector<ConsumableManagedValue, 4> destructured;
1407-
1408-
// Break down the values.
1409-
auto tupleSILTy = v.getType();
1410-
for (unsigned i = 0, e = sourceType->getNumElements(); i < e; ++i) {
1411-
SILType fieldTy = tupleSILTy.getTupleElementType(i);
1412-
auto &fieldTL = SGF.getTypeLowering(fieldTy);
1399+
// Final consumption here will be either BorrowAlways or TakeAlways.
1400+
ManagedValue v = src.getFinalManagedValue();
14131401

1414-
// This is a borrowed value, so we need to use copy on success.
1415-
ManagedValue member = SGF.B.createTupleExtract(loc, v, i, fieldTy);
1416-
// *NOTE* We leave this as getManagedSubobject so that when we get a
1417-
// destructure operation, we can pass in src.getFinalConsumption() here and
1418-
// get the correct behavior of performing the take.
1419-
auto memberCMV = getManagedSubobject(SGF, member.getValue(), fieldTL,
1420-
CastConsumptionKind::CopyOnSuccess);
1421-
destructured.push_back(memberCMV);
1422-
}
1402+
SmallVector<ConsumableManagedValue, 8> destructured;
1403+
SGF.B.emitDestructureValueOperation(
1404+
loc, v, [&](unsigned index, ManagedValue v) {
1405+
destructured.push_back({v, src.getFinalConsumption()});
1406+
});
14231407

1408+
// Break down the values.
14241409
// Recurse.
14251410
handleCase(destructured, specializedRows, outerFailure);
14261411
}

Diff for: test/SILGen/switch_ownership.swift

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// RUN: %target-swift-emit-silgen -module-name switch -enable-sil-ownership %s | %FileCheck %s
2+
//
3+
// A temporary file for testing switch code around ownership. Once SILGenPattern
4+
// refactoring is complete, this will be merged into the normal pattern file.
5+
6+
//////////////////
7+
// Declarations //
8+
//////////////////
9+
10+
class Klass {
11+
init() {}
12+
}
13+
14+
enum Foo { case A, B }
15+
16+
enum NonTrivialFoo {
17+
case A(Klass)
18+
case B(Klass)
19+
}
20+
21+
func a() {}
22+
func b() {}
23+
func c() {}
24+
func d() {}
25+
func e() {}
26+
func f() {}
27+
func g() {}
28+
29+
///////////
30+
// Tests //
31+
///////////
32+
33+
// CHECK-LABEL: sil hidden @$s6switch05test_A19_two_trivial_unions1x1yyAA3FooO_AFtF : $@convention(thin) (Foo, Foo) -> () {
34+
func test_switch_two_trivial_unions(x: Foo, y: Foo) {
35+
// CHECK: [[T0:%.*]] = tuple (%0 : $Foo, %1 : $Foo)
36+
// CHECK: ([[X:%.*]], [[Y:%.*]]) = destructure_tuple [[T0]]
37+
// CHECK: switch_enum [[Y]] : $Foo, case #Foo.A!enumelt: [[IS_CASE1:bb[0-9]+]], default [[IS_NOT_CASE1:bb[0-9]+]]
38+
39+
switch (x, y) {
40+
// CHECK: [[IS_CASE1]]:
41+
case (_, Foo.A):
42+
// CHECK: function_ref @$s6switch1ayyF
43+
a()
44+
45+
// CHECK: [[IS_NOT_CASE1]](
46+
// CHECK: switch_enum [[X]] : $Foo, case #Foo.B!enumelt: [[IS_CASE2:bb[0-9]+]], default [[IS_NOT_CASE2:bb[0-9]+]]
47+
// CHECK: [[IS_CASE2]]:
48+
case (Foo.B, _):
49+
// CHECK: function_ref @$s6switch1byyF
50+
b()
51+
52+
// CHECK: [[IS_NOT_CASE2]](
53+
// CHECK: switch_enum [[Y]] : $Foo, case #Foo.B!enumelt: [[IS_CASE3:bb[0-9]+]], default [[UNREACHABLE:bb[0-9]+]]
54+
// CHECK: [[IS_CASE3]]:
55+
case (_, Foo.B):
56+
// CHECK: function_ref @$s6switch1cyyF
57+
c()
58+
59+
// CHECK: [[UNREACHABLE]](
60+
// CHECK: unreachable
61+
}
62+
}
63+
64+
// CHECK-LABEL: sil hidden @$s6switch05test_A22_two_nontrivial_unions1x1yyAA13NonTrivialFooO_AFtF : $@convention(thin) (@guaranteed NonTrivialFoo, @guaranteed NonTrivialFoo) -> () {
65+
func test_switch_two_nontrivial_unions(x: NonTrivialFoo, y: NonTrivialFoo) {
66+
// CHECK: [[ARG0_COPY:%.*]] = copy_value %0
67+
// CHECK: [[ARG1_COPY:%.*]] = copy_value %1
68+
// CHECK: [[T0:%.*]] = tuple ([[ARG0_COPY]] : $NonTrivialFoo, [[ARG1_COPY]] : $NonTrivialFoo)
69+
// CHECK: ([[X:%.*]], [[Y:%.*]]) = destructure_tuple [[T0]]
70+
// CHECK: [[BORROWED_Y:%.*]] = begin_borrow [[Y]]
71+
// CHECK: [[BORROWED_Y_COPY:%.*]] = copy_value [[BORROWED_Y]]
72+
// CHECK: switch_enum [[BORROWED_Y_COPY]] : $NonTrivialFoo, case #NonTrivialFoo.A!enumelt.1: [[IS_CASE1:bb[0-9]+]], default [[IS_NOT_CASE1:bb[0-9]+]]
73+
74+
switch (x, y) {
75+
// CHECK: [[IS_CASE1]]({{%.*}} : @owned $Klass)
76+
case (_, NonTrivialFoo.A):
77+
// CHECK: function_ref @$s6switch1ayyF
78+
a()
79+
80+
// CHECK: [[IS_NOT_CASE1]]({{%.*}} : @owned $NonTrivialFoo):
81+
// CHECK: [[BORROWED_X:%.*]] = begin_borrow [[X]]
82+
// CHECK: [[BORROWED_X_COPY:%.*]] = copy_value [[BORROWED_X]]
83+
// CHECK: switch_enum [[BORROWED_X_COPY]] : $NonTrivialFoo, case #NonTrivialFoo.B!enumelt.1: [[IS_CASE2:bb[0-9]+]], default [[IS_NOT_CASE2:bb[0-9]+]]
84+
// CHECK: [[IS_CASE2]]({{%.*}} : @owned $Klass)
85+
case (NonTrivialFoo.B, _):
86+
// CHECK: function_ref @$s6switch1byyF
87+
b()
88+
89+
// CHECK: [[IS_NOT_CASE2]]({{%.*}} : @owned $NonTrivialFoo)
90+
// CHECK: [[Y_COPY:%.*]] = copy_value [[Y]]
91+
// CHECK: switch_enum [[Y_COPY]] : $NonTrivialFoo, case #NonTrivialFoo.B!enumelt.1: [[IS_CASE3:bb[0-9]+]], default [[UNREACHABLE:bb[0-9]+]]
92+
// CHECK: [[IS_CASE3]]({{%.*}} : @owned $Klass):
93+
case (_, NonTrivialFoo.B):
94+
// CHECK: function_ref @$s6switch1cyyF
95+
c()
96+
97+
// CHECK: [[UNREACHABLE]]({{%.*}} : @owned $NonTrivialFoo):
98+
// CHECK: unreachable
99+
}
100+
}

0 commit comments

Comments
 (0)