Skip to content

Commit 22b4802

Browse files
committed
[IRGen] Collect nc deinit metadata for outlining.
Some outlined functions call deinits for noncopyable values. These deinits require the metadata for the full type. Teach the OutliningMetadataCollector to collect the metadata for these types, when the new needsDeinit flag is set. Also add the new needsLayout flag. For now, all outlined functions need it.
1 parent 4cd073a commit 22b4802

File tree

6 files changed

+194
-20
lines changed

6 files changed

+194
-20
lines changed

lib/IRGen/GenExistential.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ namespace {
253253
asDerived().emitValueAssignWithCopy(IGF, destValue, srcValue);
254254
emitCopyOfTables(IGF, dest, src);
255255
} else {
256-
OutliningMetadataCollector collector(IGF);
256+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
257+
DeinitIsNotNeeded);
257258
collector.emitCallToOutlinedCopy(dest, src, T, *this,
258259
IsNotInitialization, IsNotTake);
259260
}
@@ -267,7 +268,8 @@ namespace {
267268
asDerived().emitValueInitializeWithCopy(IGF, destValue, srcValue);
268269
emitCopyOfTables(IGF, dest, src);
269270
} else {
270-
OutliningMetadataCollector collector(IGF);
271+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
272+
DeinitIsNotNeeded);
271273
collector.emitCallToOutlinedCopy(dest, src, T, *this,
272274
IsInitialization, IsNotTake);
273275
}
@@ -281,7 +283,8 @@ namespace {
281283
asDerived().emitValueAssignWithTake(IGF, destValue, srcValue);
282284
emitCopyOfTables(IGF, dest, src);
283285
} else {
284-
OutliningMetadataCollector collector(IGF);
286+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
287+
DeinitIsNotNeeded);
285288
collector.emitCallToOutlinedCopy(dest, src, T, *this,
286289
IsNotInitialization, IsTake);
287290
}
@@ -295,7 +298,8 @@ namespace {
295298
asDerived().emitValueInitializeWithTake(IGF, destValue, srcValue);
296299
emitCopyOfTables(IGF, dest, src);
297300
} else {
298-
OutliningMetadataCollector collector(IGF);
301+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
302+
DeinitIsNotNeeded);
299303
collector.emitCallToOutlinedCopy(dest, src, T, *this,
300304
IsInitialization, IsTake);
301305
}
@@ -307,7 +311,8 @@ namespace {
307311
Address valueAddr = projectValue(IGF, existential);
308312
asDerived().emitValueDestroy(IGF, valueAddr);
309313
} else {
310-
OutliningMetadataCollector collector(IGF);
314+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
315+
DeinitIsNotNeeded);
311316
collector.emitCallToOutlinedDestroy(existential, T, *this);
312317
}
313318
}
@@ -963,7 +968,8 @@ class OpaqueExistentialTypeInfo final :
963968
srcBuffer);
964969
} else {
965970
// Create an outlined function to avoid explosion
966-
OutliningMetadataCollector collector(IGF);
971+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
972+
DeinitIsNotNeeded);
967973
collector.emitCallToOutlinedCopy(dest, src, T, *this,
968974
IsInitialization, IsNotTake);
969975
}
@@ -979,7 +985,8 @@ class OpaqueExistentialTypeInfo final :
979985
IGF.emitMemCpy(dest, src, getLayout().getSize(IGF.IGM));
980986
} else {
981987
// Create an outlined function to avoid explosion
982-
OutliningMetadataCollector collector(IGF);
988+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
989+
DeinitIsNotNeeded);
983990
collector.emitCallToOutlinedCopy(dest, src, T, *this,
984991
IsInitialization, IsTake);
985992
}

lib/IRGen/GenType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ void LoadableTypeInfo::initializeWithCopy(IRGenFunction &IGF, Address destAddr,
184184
loadAsCopy(IGF, srcAddr, copy);
185185
initialize(IGF, copy, destAddr, true);
186186
} else {
187-
OutliningMetadataCollector collector(IGF);
187+
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
188+
DeinitIsNotNeeded);
188189
// No need to collect anything because we assume loadable types can be
189190
// loaded without enums.
190191
collector.emitCallToOutlinedCopy(

lib/IRGen/Outlining.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType ty) {
4444
auto astType = ty.getASTType();
4545
auto &ti = IGF.IGM.getTypeInfoForLowered(astType);
4646

47+
if (needsDeinit) {
48+
auto *nominal = ty.getASTType()->getAnyNominal();
49+
if (nominal && nominal->getValueTypeDestructor()) {
50+
assert(ty.isMoveOnly());
51+
collectFormalTypeMetadata(ty.getASTType());
52+
}
53+
}
54+
55+
if (!needsLayout) {
56+
return;
57+
}
58+
4759
// We don't need the metadata for fixed size types or types that are not ABI
4860
// accessible. Outlining will call the value witness of the enclosing type of
4961
// non ABI accessible field/element types.
@@ -139,11 +151,12 @@ irgen::getTypeAndGenericSignatureForManglingOutlineFunction(SILType type) {
139151
}
140152

141153
bool TypeInfo::withMetadataCollector(
142-
IRGenFunction &IGF, SILType T,
154+
IRGenFunction &IGF, SILType T, LayoutIsNeeded_t needsLayout,
155+
DeinitIsNeeded_t needsDeinit,
143156
llvm::function_ref<void(OutliningMetadataCollector &)> invocation) const {
144157
if (!T.hasLocalArchetype() &&
145158
!IGF.outliningCanCallValueWitnesses()) {
146-
OutliningMetadataCollector collector(IGF);
159+
OutliningMetadataCollector collector(IGF, needsLayout, needsDeinit);
147160
if (T.hasArchetype()) {
148161
collectMetadataForOutlining(collector, T);
149162
}
@@ -153,7 +166,7 @@ bool TypeInfo::withMetadataCollector(
153166

154167
if (!T.hasArchetype()) {
155168
// The implementation will call vwt in this case.
156-
OutliningMetadataCollector collector(IGF);
169+
OutliningMetadataCollector collector(IGF, needsLayout, needsDeinit);
157170
invocation(collector);
158171
return true;
159172
}
@@ -164,9 +177,11 @@ bool TypeInfo::withMetadataCollector(
164177
void TypeInfo::callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
165178
SILType T, IsInitialization_t isInit,
166179
IsTake_t isTake) const {
167-
if (withMetadataCollector(IGF, T, [&](auto collector) {
168-
collector.emitCallToOutlinedCopy(dest, src, T, *this, isInit, isTake);
169-
})) {
180+
if (withMetadataCollector(IGF, T, LayoutIsNeeded, DeinitIsNotNeeded,
181+
[&](auto collector) {
182+
collector.emitCallToOutlinedCopy(
183+
dest, src, T, *this, isInit, isTake);
184+
})) {
170185
return;
171186
}
172187

@@ -186,6 +201,8 @@ void OutliningMetadataCollector::emitCallToOutlinedCopy(
186201
Address dest, Address src,
187202
SILType T, const TypeInfo &ti,
188203
IsInitialization_t isInit, IsTake_t isTake) const {
204+
assert(needsLayout);
205+
assert(!needsDeinit);
189206
llvm::SmallVector<llvm::Value *, 4> args;
190207
args.push_back(IGF.Builder.CreateElementBitCast(src, ti.getStorageType())
191208
.getAddress());
@@ -359,9 +376,10 @@ void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
359376
if (IGF.IGM.getTypeLowering(T).isTrivial())
360377
return;
361378

362-
if (withMetadataCollector(IGF, T, [&](auto collector) {
363-
collector.emitCallToOutlinedDestroy(addr, T, *this);
364-
})) {
379+
if (withMetadataCollector(
380+
IGF, T, LayoutIsNeeded, DeinitIsNeeded, [&](auto collector) {
381+
collector.emitCallToOutlinedDestroy(addr, T, *this);
382+
})) {
365383
return;
366384
}
367385

@@ -370,6 +388,8 @@ void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
370388

371389
void OutliningMetadataCollector::emitCallToOutlinedDestroy(
372390
Address addr, SILType T, const TypeInfo &ti) const {
391+
assert(needsLayout);
392+
assert(needsDeinit);
373393
llvm::SmallVector<llvm::Value *, 4> args;
374394
args.push_back(IGF.Builder.CreateElementBitCast(addr, ti.getStorageType())
375395
.getAddress());

lib/IRGen/Outlining.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include "LocalTypeDataKind.h"
2121
#include "swift/Basic/LLVM.h"
2222
#include "llvm/ADT/MapVector.h"
23-
#include "LocalTypeDataKind.h"
2423

2524
namespace llvm {
2625
class Value;
@@ -41,6 +40,16 @@ class IRGenFunction;
4140
class IRGenModule;
4241
class TypeInfo;
4342

43+
enum LayoutIsNeeded_t : bool {
44+
LayoutIsNotNeeded = false,
45+
LayoutIsNeeded = true
46+
};
47+
48+
enum DeinitIsNeeded_t : bool {
49+
DeinitIsNotNeeded = false,
50+
DeinitIsNeeded = true
51+
};
52+
4453
/// A helper class for emitting outlined value operations.
4554
///
4655
/// The use-pattern for this class is:
@@ -51,12 +60,17 @@ class TypeInfo;
5160
class OutliningMetadataCollector {
5261
public:
5362
IRGenFunction &IGF;
63+
const unsigned needsLayout : 1;
64+
const unsigned needsDeinit : 1;
65+
5466
private:
5567
llvm::MapVector<LocalTypeDataKey, llvm::Value *> Values;
5668
friend class IRGenModule;
5769

5870
public:
59-
OutliningMetadataCollector(IRGenFunction &IGF) : IGF(IGF) {}
71+
OutliningMetadataCollector(IRGenFunction &IGF, LayoutIsNeeded_t needsLayout,
72+
DeinitIsNeeded_t needsDeinitTypes)
73+
: IGF(IGF), needsLayout(needsLayout), needsDeinit(needsDeinitTypes) {}
6074

6175
void collectTypeMetadataForLayout(SILType type);
6276

lib/IRGen/TypeInfo.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#define SWIFT_IRGEN_TYPEINFO_H
2727

2828
#include "IRGen.h"
29+
#include "Outlining.h"
2930
#include "swift/AST/ReferenceCounting.h"
3031
#include "llvm/ADT/MapVector.h"
3132

@@ -575,7 +576,8 @@ class TypeInfo {
575576
/// Returns whether there was an appropriate metadata collector (and whether
576577
/// \p invocation was called.
577578
bool withMetadataCollector(
578-
IRGenFunction &IGF, SILType T,
579+
IRGenFunction &IGF, SILType T, LayoutIsNeeded_t needsLayout,
580+
DeinitIsNeeded_t needsDeinit,
579581
llvm::function_ref<void(OutliningMetadataCollector &)> invocation) const;
580582

581583
void callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// RUN: %target-swift-emit-irgen -O \
2+
// RUN: -enable-experimental-feature NoncopyableGenerics \
3+
// RUN: -disable-type-layout \
4+
// RUN: %s \
5+
// RUN: | \
6+
// RUN: %FileCheck %s
7+
8+
@_silgen_name("external_symbol")
9+
func external_symbol()
10+
11+
public class C<T> {
12+
deinit {
13+
external_symbol()
14+
}
15+
}
16+
17+
public struct InnerDeinitingReleasableNC<T> : ~Copyable {
18+
public let i1: Int
19+
public let i2: Int
20+
public let i3: Int
21+
public let i4: Int
22+
public let c1: C<T>
23+
public let c2: C<T>
24+
public let c3: C<T>
25+
public let c4: C<T>
26+
27+
deinit {
28+
external_symbol()
29+
}
30+
}
31+
32+
public struct InnerDeinitingDestructableNC<T> : ~Copyable {
33+
public let t: T
34+
public let i1: Int
35+
public let i2: Int
36+
public let i3: Int
37+
public let i4: Int
38+
public let c1: C<T>
39+
public let c2: C<T>
40+
public let c3: C<T>
41+
public let c4: C<T>
42+
43+
deinit {
44+
external_symbol()
45+
}
46+
}
47+
48+
public struct OuterDeinitingNC_1<T> : ~Copyable {
49+
public let i1: Int
50+
public let c1: C<T>
51+
public let i: InnerDeinitingReleasableNC<T>
52+
deinit {
53+
external_symbol()
54+
}
55+
}
56+
57+
public struct OuterNC_1<T> : ~Copyable {
58+
public let i1: Int
59+
public let c1: C<T>
60+
public let i: InnerDeinitingReleasableNC<T>
61+
}
62+
63+
public struct OuterNC_2<T> : ~Copyable {
64+
public let i1: Int
65+
public let c1: C<T>
66+
public let i: InnerDeinitingDestructableNC<T>
67+
}
68+
69+
// Destroyed value:
70+
// - has deinit
71+
// On lifetime end:
72+
// - call deinit
73+
// CHECK-LABEL: define{{.*}} @"$s24moveonly_value_functions22takeOuterDeinitingNC_1yyAA0efG2_1VyxGnlF"(
74+
// CHECK-SAME: ptr{{.*}} %0,
75+
// CHECK-SAME: ptr %T)
76+
// CHECK-SAME: {
77+
// CHECK: [[RESPONSE:%[^,]+]] = call{{.*}} @"$s24moveonly_value_functions18OuterDeinitingNC_1VMa"(
78+
// : i64 0,
79+
// CHECK-SAME: ptr %T)
80+
// CHECK: [[OUTER_DEINITING_NC_1_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[RESPONSE]]
81+
// CHECK: call{{.*}} @"$s24moveonly_value_functions18OuterDeinitingNC_1VfD"(
82+
// CHECK-SAME: ptr [[OUTER_DEINITING_NC_1_METADATA]],
83+
// CHECK-SAME: ptr{{.*}} %0)
84+
// CHECK: }
85+
public func takeOuterDeinitingNC_1<T>(_ t: consuming OuterDeinitingNC_1<T>) {
86+
external_symbol()
87+
}
88+
89+
// If the destroyed value has no deinit, is releasable, and contains a
90+
// noncopyable value with a deinit, call the outlined destroy function.
91+
// Destroyed value:
92+
// - has NO deinit
93+
// - contains value type with deinit
94+
// - is NOT releasable
95+
// On lifetime end:
96+
// - call outlined destroy destroy
97+
// CHECK-LABEL: define{{.*}} @"$s24moveonly_value_functions13takeOuterNC_2yyAA0eF2_2VyxGnlF"(
98+
// CHECK-SAME: ptr{{.*}} %0,
99+
// CHECK-SAME: ptr %T)
100+
// CHECK-SAME: {
101+
// CHECK: [[RESPONSE:%[^,]+]] = call{{.*}} @"$s24moveonly_value_functions28InnerDeinitingDestructableNCVMa"(
102+
// CHECK-SAME: i64 0,
103+
// CHECK-SAME: ptr %T)
104+
// CHECK: [[INNER_DEINITING_DESTRUCTABLE_NC_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[RESPONSE]]
105+
// CHECK: call{{.*}} @"$s24moveonly_value_functions9OuterNC_2VyxGlWOh"(
106+
// CHECK-SAME: ptr %0,
107+
// CHECK-SAME: ptr %T,
108+
// CHECK-SAME: ptr [[INNER_DEINITING_DESTRUCTABLE_NC_METADATA]],
109+
// : ptr %4)
110+
// CHECK: }
111+
112+
// Verify that the outlined destroy function takes the metadata for the
113+
// move-only-with-deinit type InnerDeinitingDestructable<T> and passes it along
114+
// to that deinit.
115+
// $s24moveonly_value_functions9OuterNC_2VyxGlWOh ---> outlined destroy of moveonly_value_functions.OuterNC_2<A>
116+
// CHECK-LABEL: define{{.*}} @"$s24moveonly_value_functions9OuterNC_2VyxGlWOh"(
117+
// CHECK-SAME: ptr %0,
118+
// CHECK-SAME: ptr %T,
119+
// CHECK-SAME: ptr %"InnerDeinitingDestructableNC<T>",
120+
// CHECK-SAME: ptr %"OuterNC_2<T>")
121+
// CHECK-SAME: {
122+
// ...
123+
// ...
124+
// CHECK: call{{.*}} @"$s24moveonly_value_functions28InnerDeinitingDestructableNCVfD"(
125+
// CHECK-SAME: ptr %"InnerDeinitingDestructableNC<T>",
126+
// : ptr noalias swiftself %3)
127+
// CHECK: }
128+
public func takeOuterNC_2<T>(_ o: consuming OuterNC_2<T>) {
129+
external_symbol()
130+
}

0 commit comments

Comments
 (0)