Skip to content

Commit 668ccd7

Browse files
authored
Merge pull request #24893 from gottesmm/swift-5.1-branch-rdar49903264
[5.1][silgenpattern] When binding values, use a ManagedValue instead of an RValue to avoid implicitly exploding tuples.
2 parents ea2cab3 + 060fbc4 commit 668ccd7

File tree

11 files changed

+176
-21
lines changed

11 files changed

+176
-21
lines changed

lib/SILGen/ManagedValue.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ ManagedValue ManagedValue::formalAccessCopy(SILGenFunction &SGF,
5757

5858
/// Store a copy of this value with independent ownership into the given
5959
/// uninitialized address.
60-
void ManagedValue::copyInto(SILGenFunction &SGF, SILValue dest,
61-
SILLocation loc) {
60+
void ManagedValue::copyInto(SILGenFunction &SGF, SILLocation loc,
61+
SILValue dest) {
6262
auto &lowering = SGF.getTypeLowering(getType());
6363
if (lowering.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
6464
SGF.B.createCopyAddr(loc, getValue(), dest, IsNotTake, IsInitialization);
@@ -69,6 +69,12 @@ void ManagedValue::copyInto(SILGenFunction &SGF, SILValue dest,
6969
lowering.emitStoreOfCopy(SGF.B, loc, copy, dest, IsInitialization);
7070
}
7171

72+
void ManagedValue::copyInto(SILGenFunction &SGF, SILLocation loc,
73+
Initialization *dest) {
74+
dest->copyOrInitValueInto(SGF, loc, *this, /*isInit*/ false);
75+
dest->finishInitialization(SGF);
76+
}
77+
7278
/// This is the same operation as 'copy', but works on +0 values that don't
7379
/// have cleanups. It returns a +1 value with one.
7480
ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &SGF, SILLocation loc) {

lib/SILGen/ManagedValue.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,6 @@ class ManagedValue {
268268
/// formal evaluation scope.
269269
ManagedValue formalAccessCopy(SILGenFunction &SGF, SILLocation loc);
270270

271-
/// Store a copy of this value with independent ownership into the given
272-
/// uninitialized address.
273-
void copyInto(SILGenFunction &SGF, SILValue dest, SILLocation loc);
274-
275271
/// This is the same operation as 'copy', but works on +0 values that don't
276272
/// have cleanups. It returns a +1 value with one.
277273
ManagedValue copyUnmanaged(SILGenFunction &SGF, SILLocation loc);
@@ -333,7 +329,15 @@ class ManagedValue {
333329
/// \param loc - the AST location to associate with emitted instructions.
334330
/// \param address - the address to assign to.
335331
void assignInto(SILGenFunction &SGF, SILLocation loc, SILValue address);
336-
332+
333+
/// Store a copy of this value with independent ownership into the given
334+
/// uninitialized address.
335+
void copyInto(SILGenFunction &SGF, SILLocation loc, SILValue dest);
336+
337+
/// Store a copy of this value with independent ownership into the given
338+
/// initialization \p dest.
339+
void copyInto(SILGenFunction &SGF, SILLocation loc, Initialization *dest);
340+
337341
explicit operator bool() const {
338342
// "InContext" is not considered false.
339343
return bool(getValue()) || valueAndFlag.getInt();

lib/SILGen/SILGenDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ copyOrInitValueIntoSingleBuffer(SILGenFunction &SGF, SILLocation loc,
205205
assert(value.getValue() != destAddr && "copying in place?!");
206206
SILValue accessAddr =
207207
UnenforcedFormalAccess::enter(SGF, loc, destAddr, SILAccessKind::Modify);
208-
value.copyInto(SGF, accessAddr, loc);
208+
value.copyInto(SGF, loc, accessAddr);
209209
return;
210210
}
211211

@@ -627,7 +627,7 @@ class ReferenceStorageInitialization : public Initialization {
627627
if (isInit)
628628
value.forwardInto(SGF, loc, address);
629629
else
630-
value.copyInto(SGF, address, loc);
630+
value.copyInto(SGF, loc, address);
631631
}
632632

633633
void finishUninitialized(SILGenFunction &SGF) override {

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,7 @@ makeBaseConsumableMaterializedRValue(SILGenFunction &SGF,
17051705
if (!base.getType().isAddress() || isBorrowed) {
17061706
auto tmp = SGF.emitTemporaryAllocation(loc, base.getType());
17071707
if (isBorrowed)
1708-
base.copyInto(SGF, tmp, loc);
1708+
base.copyInto(SGF, loc, tmp);
17091709
else
17101710
base.forwardInto(SGF, loc, tmp);
17111711
return SGF.emitManagedBufferWithCleanup(tmp);

lib/SILGen/SILGenPattern.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,12 +1193,11 @@ void PatternMatchEmission::bindVariable(Pattern *pattern, VarDecl *var,
11931193

11941194
// Initialize the variable value.
11951195
InitializationPtr init = SGF.emitInitializationForVarDecl(var, immutable);
1196-
CanType formalValueType = pattern->getType()->getCanonicalType();
1197-
RValue rv(SGF, pattern, formalValueType, value.getFinalManagedValue());
1196+
auto mv = value.getFinalManagedValue();
11981197
if (shouldTake(value, isIrrefutable)) {
1199-
std::move(rv).forwardInto(SGF, pattern, init.get());
1198+
mv.forwardInto(SGF, pattern, init.get());
12001199
} else {
1201-
std::move(rv).copyInto(SGF, pattern, init.get());
1200+
mv.copyInto(SGF, pattern, init.get());
12021201
}
12031202
}
12041203

lib/SILGen/SILGenProlog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
199199
if (element.hasCleanup())
200200
element.forwardInto(SGF, loc, elementBuffer);
201201
else
202-
element.copyInto(SGF, elementBuffer, loc);
202+
element.copyInto(SGF, loc, elementBuffer);
203203
}
204204
return SGF.emitManagedRValueWithCleanup(buffer);
205205
}

test/Inputs/resilient_struct.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ public struct ResilientDouble {
7878
}
7979
}
8080

81-
public class Referent {}
81+
public class Referent {
82+
public init() {}
83+
}
8284

8385
public struct ResilientWeakRef {
8486
public weak var ref: Referent?
@@ -90,8 +92,21 @@ public struct ResilientWeakRef {
9092

9193
public struct ResilientRef {
9294
public var r: Referent
95+
96+
public init(r: Referent) { self.r = r }
9397
}
9498

9599
public struct ResilientWithInternalField {
96100
var x: Int
97101
}
102+
103+
// Tuple parameters with resilient structs
104+
public class Subject {}
105+
106+
public struct Container {
107+
public var s: Subject
108+
}
109+
110+
public struct PairContainer {
111+
public var pair : (Container, Container)
112+
}

test/Interpreter/switch_objc.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-run-simple-swift
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: objc_interop
5+
6+
import StdlibUnittest
7+
import Foundation
8+
9+
var SwitchTestSuite = TestSuite("SwitchObjC")
10+
defer { runAllTests() }
11+
12+
SwitchTestSuite.test("Resilient Type Tuple Initialization Construction") {
13+
// This test make sure that this works for URL specifically. There is a
14+
// separate artificial test case in switch_resilience that uses our own
15+
// resilient type.
16+
enum Enum {
17+
case first(url: URL, void: Void)
18+
}
19+
20+
func getEnum() -> Enum {
21+
let url = URL(string: "http://foobar.com")!
22+
return .first(url: url, void: ())
23+
}
24+
func getBool() -> Bool { return false }
25+
26+
switch getEnum() {
27+
case let .first(x, y) where getBool():
28+
print("first")
29+
case .first:
30+
print("second")
31+
}
32+
33+
switch getEnum() {
34+
case let .first(value) where getBool():
35+
print("third")
36+
case .first:
37+
print("fourth")
38+
}
39+
print("done")
40+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift-dylib(%t/%target-library-name(resilient_struct)) %S/../Inputs/resilient_struct.swift -emit-module -emit-module-path %t/resilient_struct.swiftmodule -module-name resilient_struct -I%t -L%t -enable-library-evolution
3+
// RUN: %target-codesign %t/%target-library-name(resilient_struct)
4+
// RUN: %target-swiftc_driver -I %t -L %t %s -o %t/switch_resilience -lresilient_struct %target-rpath(%t)
5+
// RUN: %target-codesign %t/switch_resilience
6+
// RUN: %target-run %t/switch_resilience
7+
8+
// REQUIRES: executable_test
9+
10+
import StdlibUnittest
11+
import resilient_struct
12+
13+
var SwitchResilienceTestSuite = TestSuite("SwitchResilience")
14+
defer { runAllTests() }
15+
16+
enum Enum {
17+
case first(url: ResilientRef, void: Void)
18+
}
19+
20+
func getEnum() -> Enum {
21+
let url = ResilientRef(r: Referent())
22+
return .first(url: url, void: ())
23+
}
24+
func getBool() -> Bool { return false }
25+
func urlUser(_ u: ResilientRef) {}
26+
func kraken() {}
27+
28+
SwitchResilienceTestSuite.test("Resilient Type Tuple Initialization") {
29+
switch getEnum() {
30+
case let .first(value) where getBool():
31+
urlUser(value.0)
32+
case .first:
33+
kraken()
34+
}
35+
kraken()
36+
}

test/SILGen/switch_resilience.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule %S/../Inputs/resilient_struct.swift
3+
// RUN: %target-swift-emit-silgen -I %t %s | %FileCheck %s
4+
5+
import resilient_struct
6+
7+
// CHECK-LABEL: sil hidden [ossa] @$s17switch_resilience29resilientTupleEltCaseEnumTestyyF : $@convention(thin) () -> () {
8+
// CHECK: bb0:
9+
// CHECK: [[STACK_SLOT:%.*]] = alloc_stack $Enum
10+
//
11+
// CHECK: bb1:
12+
// CHECK: [[VALUE:%.*]] = unchecked_take_enum_data_addr [[STACK_SLOT]] : $*Enum
13+
// CHECK: [[STACK_SLOT_COPY:%.*]] = alloc_stack $(url: ResilientRef, void: ()), let, name "value"
14+
// CHECK: copy_addr [[VALUE]] to [initialization] [[STACK_SLOT_COPY]]
15+
// CHECK: cond_br {{%.*}}, bb2, bb3
16+
//
17+
// CHECK: bb2:
18+
// CHECK: destroy_addr [[STACK_SLOT_COPY]]
19+
// CHECK-NEXT: dealloc_stack [[STACK_SLOT_COPY]]
20+
// CHECK-NEXT: destroy_addr [[VALUE]]
21+
// CHECK-NEXT: dealloc_stack [[STACK_SLOT]]
22+
// CHECK-NEXT: br bb4
23+
//
24+
// CHECK: bb3:
25+
// CHECK-NEXT: destroy_addr [[STACK_SLOT_COPY]]
26+
// CHECK-NEXT: dealloc_stack [[STACK_SLOT_COPY]]
27+
// CHECK-NEXT: [[REPROJECT:%.*]] = tuple_element_addr [[VALUE]]
28+
// CHECK: destroy_addr [[REPROJECT]]
29+
// CHECK-NEXT: dealloc_stack [[STACK_SLOT]]
30+
// CHECK: br bb4
31+
//
32+
// CHECK: } // end sil function '$s17switch_resilience29resilientTupleEltCaseEnumTestyyF'
33+
func resilientTupleEltCaseEnumTest() {
34+
enum Enum {
35+
case first(url: ResilientRef, void: Void)
36+
}
37+
38+
func getEnum() -> Enum {
39+
let url = ResilientRef(r: Referent())
40+
return .first(url: url, void: ())
41+
}
42+
func getBool() -> Bool { return false }
43+
func urlUser(_ u: ResilientRef) {}
44+
func kraken() {}
45+
46+
switch getEnum() {
47+
case let .first(value) where getBool():
48+
urlUser(value.0)
49+
case .first:
50+
kraken()
51+
}
52+
}

test/SILGen/switch_var.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ struct X : P { func p() {} }
189189
struct Y : P { func p() {} }
190190
struct Z : P { func p() {} }
191191

192-
// CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_41pyAA1P_p_tF
192+
// CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_41pyAA1P_p_tF : $@convention(thin) (@in_guaranteed P) -> () {
193193
func test_var_4(p p: P) {
194194
// CHECK: function_ref @$s10switch_var3fooSiyF
195195
switch (p, foo()) {
@@ -275,12 +275,14 @@ func test_var_4(p p: P) {
275275
// CHECK: tuple_element_addr [[READ]] : {{.*}}, 1
276276
// CHECK: function_ref @$s10switch_var1c1xySi_tF
277277
// CHECK: destroy_value [[ZADDR]]
278+
// CHECK-NEXT: destroy_addr [[PAIR]]
278279
// CHECK-NEXT: dealloc_stack [[PAIR]]
279280
// CHECK: br [[CONT]]
280281
c(x: z.1)
281282

282283
// CHECK: [[DFLT_NO_CASE3]]:
283-
// CHECK: destroy_value [[ZADDR]]
284+
// CHECK-NEXT: destroy_value [[ZADDR]]
285+
// CHECK-NOT: destroy_addr
284286
case (_, var w):
285287
// CHECK: [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 0
286288
// CHECK: [[WADDR:%.*]] = alloc_box ${ var Int }
@@ -289,9 +291,10 @@ func test_var_4(p p: P) {
289291
// CHECK: load [trivial] [[READ]]
290292
// CHECK: function_ref @$s10switch_var1d1xySi_tF
291293
// CHECK: destroy_value [[WADDR]]
292-
// CHECK: destroy_addr [[PAIR_0]] : $*P
293-
// CHECK: dealloc_stack [[PAIR]]
294-
// CHECK: br [[CONT]]
294+
// CHECK-NEXT: destroy_addr [[PAIR_0]] : $*P
295+
// CHECK-NEXT: dealloc_stack [[PAIR]]
296+
// CHECK-NEXT: dealloc_stack
297+
// CHECK-NEXT: br [[CONT]]
295298
d(x: w)
296299
}
297300
e()

0 commit comments

Comments
 (0)