Skip to content

Commit f8e3e40

Browse files
committed
IRGen: Bind generic params for generic deinit call.
1 parent 8c64b8a commit f8e3e40

File tree

7 files changed

+149
-45
lines changed

7 files changed

+149
-45
lines changed

lib/IRGen/GenExistential.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,8 @@ namespace {
806806
Size size, Alignment align, \
807807
bool isOptional) \
808808
: ScalarExistentialTypeInfoBase(storedProtocols, ty, size, \
809-
spareBits, align, IsTriviallyDestroyable, IsFixedSize) {} \
809+
spareBits, align, IsTriviallyDestroyable,\
810+
IsCopyable, IsFixedSize) {} \
810811
TypeLayoutEntry \
811812
*buildTypeLayoutEntry(IRGenModule &IGM, \
812813
SILType T, \

lib/IRGen/GenType.cpp

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
#include "EnumPayload.h"
3838
#include "LegacyLayoutFormat.h"
3939
#include "LoadableTypeInfo.h"
40+
#include "GenCall.h"
4041
#include "GenMeta.h"
42+
#include "GenPoly.h"
4143
#include "GenProto.h"
4244
#include "GenType.h"
4345
#include "IRGenFunction.h"
@@ -2856,8 +2858,9 @@ void TypeInfo::verify(IRGenTypeVerifierFunction &IGF,
28562858

28572859
static bool tryEmitDeinitCall(IRGenFunction &IGF,
28582860
SILType T,
2859-
llvm::function_ref<void (CallEmission*)> direct,
2860-
llvm::function_ref<void (CallEmission*)> indirect) {
2861+
llvm::function_ref<void (Explosion &)> direct,
2862+
llvm::function_ref<Address ()> indirect,
2863+
llvm::function_ref<void ()> indirectCleanup) {
28612864
auto ty = T.getASTType();
28622865
auto nominal = ty->getAnyNominal();
28632866
// We are only concerned with move-only type deinits here.
@@ -2888,54 +2891,96 @@ static bool tryEmitDeinitCall(IRGenFunction &IGF,
28882891
substitutions,
28892892
IGF.IGM.getMaximalTypeExpansionContext()),
28902893
substitutions);
2891-
Callee deinitCallee(std::move(info), deinitFP, nullptr);
2892-
auto callEmission = getCallEmission(IGF, nullptr, std::move(deinitCallee));
2893-
callEmission->begin();
2894+
2895+
bool isIndirect;
2896+
Address indirectArg;
2897+
Explosion directArg;
28942898
switch (deinitTy->getParameters()[0].getConvention()) {
28952899
case ParameterConvention::Direct_Owned:
2896-
direct(callEmission.get());
2900+
isIndirect = false;
2901+
direct(directArg);
28972902
break;
28982903
case ParameterConvention::Indirect_In:
2899-
indirect(callEmission.get());
2904+
isIndirect = true;
2905+
indirectArg = indirect();
29002906
break;
29012907
default:
29022908
llvm_unreachable("move-only deinit should only have consuming parameter convention");
29032909
}
2910+
2911+
// If the deinit's convention has a special `self` parameter, then the
2912+
// (pointer to) the value being destroyed is that parameter.
2913+
llvm::Value *self = nullptr;
2914+
if (hasSelfContextParameter(deinitTy)) {
2915+
self = isIndirect ? indirectArg.getAddress() : directArg.claimNext();
2916+
assert(directArg.empty()
2917+
&& "direct param (if any) should be a single pointer if "
2918+
"it's the swiftself param");
2919+
}
2920+
2921+
GenericContextScope scope(IGF.IGM,
2922+
nominal->getGenericSignature().getCanonicalSignature());
2923+
2924+
Callee deinitCallee(std::move(info), deinitFP, self);
2925+
auto callEmission = getCallEmission(IGF, self, std::move(deinitCallee));
2926+
callEmission->begin();
2927+
// Pass the parameter if it wasn't already the by-convention self parameter.
2928+
if (!self) {
2929+
if (isIndirect) {
2930+
directArg.add(indirectArg.getAddress());
2931+
}
2932+
}
2933+
if (hasPolymorphicParameters(deinitTy)) {
2934+
emitPolymorphicArguments(IGF, deinitTy, substitutions, nullptr,
2935+
directArg);
2936+
}
2937+
callEmission->setArgs(directArg, /*outlined*/ false, /*witness*/nullptr);
29042938
Explosion nothing;
29052939
callEmission->emitToExplosion(nothing, /*isOutlined*/ false);
29062940
callEmission->end();
2941+
if (isIndirect) {
2942+
indirectCleanup();
2943+
}
29072944
return true;
29082945
}
29092946

29102947
bool irgen::tryEmitConsumeUsingDeinit(IRGenFunction &IGF, Explosion &explosion,
29112948
SILType T) {
29122949
const LoadableTypeInfo *ti = cast<LoadableTypeInfo>(&IGF.getTypeInfo(T));
2950+
StackAddress temporary;
29132951
return tryEmitDeinitCall(IGF, T,
29142952
// Direct parameter case
2915-
[&](CallEmission *deinitFn) {
2916-
Explosion arg;
2953+
[&](Explosion &arg) {
29172954
ti->reexplode(IGF, explosion, arg);
2918-
deinitFn->setArgs(arg, /*outlined*/ false, nullptr);
29192955
},
2920-
// Indirect parameter case
2921-
[&](CallEmission *deinitFn) {
2922-
llvm_unreachable("todo");
2956+
// Indirect parameter setup
2957+
[&]() -> Address {
2958+
// Allocate stack space to store the indirect argument, and forward our
2959+
// value into it. The deinit will consume the value in memory.
2960+
temporary = ti->allocateStack(IGF, T, "deinit.arg");
2961+
ti->initialize(IGF, explosion, temporary.getAddress(), /*outlined*/false);
2962+
return temporary.getAddress();
2963+
},
2964+
// Indirect parameter teardown
2965+
[&]{
2966+
// End the lifetime of the stack allocation.
2967+
ti->deallocateStack(IGF, temporary, T);
29232968
});
29242969
}
29252970

29262971
bool irgen::tryEmitDestroyUsingDeinit(IRGenFunction &IGF, Address address,
29272972
SILType T) {
29282973
return tryEmitDeinitCall(IGF, T,
29292974
// Direct parameter case
2930-
[&](CallEmission *deinitFn) {
2975+
[&](Explosion &arg) {
29312976
// Load the value from the address.
29322977
auto *ti = cast<LoadableTypeInfo>(&IGF.getTypeInfo(T));
2933-
Explosion arg;
29342978
ti->loadAsTake(IGF, address, arg);
2935-
deinitFn->setArgs(arg, /*outlined*/ false, nullptr);
29362979
},
2937-
// Indirect parameter case
2938-
[&](CallEmission *deinitFn) {
2939-
llvm_unreachable("todo");
2940-
});
2980+
// Indirect parameter setup
2981+
[&]() -> Address {
2982+
return address;
2983+
},
2984+
// Indirect parameter teardown
2985+
[&]{ /* nothing to do */ });
29412986
}

lib/IRGen/TypeLayout.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ static std::string scalarToString(ScalarKind kind) {
406406
case ScalarKind::BlockReference: return "BlockReference";
407407
case ScalarKind::BridgeReference: return "BridgeReference";
408408
case ScalarKind::ObjCReference: return "ObjCReference";
409-
case ScalarKind::POD: return "POD";
409+
case ScalarKind::TriviallyDestroyable: return "TriviallyDestroyable";
410410
case ScalarKind::Immovable: return "Immovable";
411411
case ScalarKind::BlockStorage: return "BlockStorage";
412412
case ScalarKind::ThickFunc: return "ThickFunc";
@@ -2182,7 +2182,7 @@ llvm::Constant *
21822182
EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
21832183
GenericSignature genericSig) const {
21842184
switch (copyDestroyKind(IGM)) {
2185-
case CopyDestroyStrategy::POD:
2185+
case CopyDestroyStrategy::TriviallyDestroyable:
21862186
case CopyDestroyStrategy::Normal: {
21872187
return nullptr;
21882188
}
@@ -2217,7 +2217,7 @@ bool EnumTypeLayoutEntry::refCountString(IRGenModule &IGM,
22172217
LayoutStringBuilder &B,
22182218
GenericSignature genericSig) const {
22192219
switch (copyDestroyKind(IGM)) {
2220-
case CopyDestroyStrategy::POD: {
2220+
case CopyDestroyStrategy::TriviallyDestroyable: {
22212221
auto size = fixedSize(IGM);
22222222
assert(size && "POD should not have dynamic size");
22232223
B.addSkip(size->getValue());
@@ -2247,15 +2247,9 @@ void EnumTypeLayoutEntry::computeProperties() {
22472247
}
22482248

22492249
EnumTypeLayoutEntry::CopyDestroyStrategy
2250-
<<<<<<< HEAD
22512250
EnumTypeLayoutEntry::copyDestroyKind(IRGenModule &IGM) const {
2252-
if (isPOD()) {
2253-
return POD;
2254-
=======
2255-
EnumTypeLayoutEntry::copyDestroyKind(IRGenFunction &IGF) const {
22562251
if (isTriviallyDestroyable()) {
22572252
return TriviallyDestroyable;
2258-
>>>>>>> eb015805016 (IRGen: Rename internal 'POD' references to 'TriviallyDestroyable'.)
22592253
} else if (isSingleton()) {
22602254
return ForwardToPayload;
22612255
} else if (cases.size() == 1 && numEmptyCases <= 1 &&
@@ -2580,13 +2574,8 @@ void EnumTypeLayoutEntry::initializeSinglePayloadEnum(IRGenFunction &IGF,
25802574
auto &IGM = IGF.IGM;
25812575
auto &Builder = IGF.Builder;
25822576

2583-
<<<<<<< HEAD
25842577
switch (copyDestroyKind(IGM)) {
2585-
case POD: {
2586-
=======
2587-
switch (copyDestroyKind(IGF)) {
25882578
case TriviallyDestroyable: {
2589-
>>>>>>> eb015805016 (IRGen: Rename internal 'POD' references to 'TriviallyDestroyable'.)
25902579
emitMemCpy(IGF, dest, src, size(IGF));
25912580
break;
25922581
}
@@ -2644,13 +2633,8 @@ void EnumTypeLayoutEntry::assignSinglePayloadEnum(IRGenFunction &IGF,
26442633
auto &IGM = IGF.IGM;
26452634
auto &Builder = IGF.Builder;
26462635

2647-
<<<<<<< HEAD
26482636
switch (copyDestroyKind(IGM)) {
2649-
case POD: {
2650-
=======
2651-
switch (copyDestroyKind(IGF)) {
26522637
case TriviallyDestroyable: {
2653-
>>>>>>> eb015805016 (IRGen: Rename internal 'POD' references to 'TriviallyDestroyable'.)
26542638
emitMemCpy(IGF, dest, src, size(IGF));
26552639
break;
26562640
}
@@ -2837,13 +2821,8 @@ void EnumTypeLayoutEntry::initializeMultiPayloadEnum(IRGenFunction &IGF,
28372821

28382822
void EnumTypeLayoutEntry::destroySinglePayloadEnum(IRGenFunction &IGF,
28392823
Address addr) const {
2840-
<<<<<<< HEAD
28412824
switch (copyDestroyKind(IGF.IGM)) {
2842-
case POD: {
2843-
=======
2844-
switch (copyDestroyKind(IGF)) {
28452825
case TriviallyDestroyable: {
2846-
>>>>>>> eb015805016 (IRGen: Rename internal 'POD' references to 'TriviallyDestroyable'.)
28472826
break;
28482827
}
28492828
case ForwardToPayload:

test/IRGen/moveonly_deinit.sil

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// RUN: %{python} %utils/chex.py < %s > %t/moveonly_deinit.sil
33
// RUN: %target-swift-frontend -enable-experimental-move-only -emit-ir %t/moveonly_deinit.sil | %FileCheck %t/moveonly_deinit.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
44

5+
// UNSUPPORTED: CPU=arm64e
6+
57
import Builtin
68
import Swift
79

@@ -118,6 +120,28 @@ struct MOSingleRefcountLikeStructNoDeinit {
118120
var x: C
119121
}
120122

123+
// Very large structs will use indirect conventions for their deinit.
124+
125+
@_moveOnly
126+
struct MOVeryBigStructDeinit {
127+
var x: Int, y: Int, z: Int, w: Int, a: Int, b: Int, c: Int, d: Int
128+
129+
deinit
130+
}
131+
132+
// Generic structs have equally generic deinits.
133+
134+
protocol P {}
135+
extension Int: P {}
136+
137+
@_moveOnly
138+
struct MOGenericDeinit<T: P, U> {
139+
var t: T
140+
var u: U
141+
142+
deinit
143+
}
144+
121145
// CHECK-LABEL: define{{.*}}@destroy_struct_value(
122146
// CHECK-NEXT: entry:
123147
// CHECK-NEXT: call{{.*}}@destroy_struct(
@@ -210,6 +234,46 @@ entry(%b : $MOComboEnum):
210234
// CHECK: [[CLASS]]:
211235
// CHECK: call {{.*}} @swift_release
212236

237+
// CHECK-LABEL: define{{.*}}@destroy_very_big_direct(
238+
// CHECK: call {{.*}} @destroy_big(
239+
sil @destroy_very_big_direct : $@convention(thin) (@owned MOVeryBigStructDeinit) -> () {
240+
entry(%b : $MOVeryBigStructDeinit):
241+
release_value %b : $MOVeryBigStructDeinit
242+
return undef : $()
243+
}
244+
245+
// CHECK-LABEL: define{{.*}}@destroy_very_big_indirect(
246+
// CHECK: call {{.*}} @destroy_big(
247+
sil @destroy_very_big_indirect : $@convention(thin) (@in MOVeryBigStructDeinit) -> () {
248+
entry(%b : $*MOVeryBigStructDeinit):
249+
destroy_addr %b : $*MOVeryBigStructDeinit
250+
return undef : $()
251+
}
252+
253+
// CHECK-LABEL: define{{.*}}@destroy_generic_instance_t(
254+
// CHECK: call {{.*}} @destroy_generic(
255+
sil @destroy_generic_instance_t : $@convention(thin) (@owned MOGenericDeinit<Int, Int>) -> () {
256+
entry(%b : $MOGenericDeinit<Int, Int>):
257+
release_value %b : $MOGenericDeinit<Int, Int>
258+
return undef : $()
259+
}
260+
261+
// CHECK-LABEL: define{{.*}}@destroy_generic_instance_nt(
262+
// CHECK: call {{.*}} @destroy_generic(
263+
sil @destroy_generic_instance_nt : $@convention(thin) (@owned MOGenericDeinit<Int, C>) -> () {
264+
entry(%b : $MOGenericDeinit<Int, C>):
265+
release_value %b : $MOGenericDeinit<Int, C>
266+
return undef : $()
267+
}
268+
269+
// CHECK-LABEL: define{{.*}}@destroy_generic_poly(
270+
// CHECK: call {{.*}} @destroy_generic(
271+
sil @destroy_generic_poly : $@convention(thin) <U, T: P> (@in MOGenericDeinit<T, U>) -> () {
272+
entry(%b : $*MOGenericDeinit<T, U>):
273+
destroy_addr %b : $*MOGenericDeinit<T, U>
274+
return undef : $()
275+
}
276+
213277
// CHECK-LABEL: define{{.*}}@box_struct(
214278
// CHECK: call {{.*}} @swift_allocObject({{.*}} %swift.full_boxmetadata* @[[BOX_STRUCT_METADATA]],
215279

@@ -232,13 +296,18 @@ sil @destroy_intlike_struct : $@convention(method) (@owned MOIntLikeStruct) -> (
232296
sil @destroy_empty_struct : $@convention(method) (@owned MOEmptyStruct) -> ()
233297
sil @destroy_single_refcount_like_struct : $@convention(method) (@owned MOSingleRefcountLikeStruct) -> ()
234298

299+
sil @destroy_big : $@convention(method) (@in MOVeryBigStructDeinit) -> ()
300+
sil @destroy_generic : $@convention(method) <T: P, U> (@in MOGenericDeinit<T, U>) -> ()
301+
235302
sil_vtable C {}
236303

237304
sil_moveonlydeinit MOStruct { @destroy_struct }
238305
sil_moveonlydeinit MOEnum { @destroy_enum }
239306
sil_moveonlydeinit MOEmptyStruct { @destroy_empty_struct }
240307
sil_moveonlydeinit MOIntLikeStruct { @destroy_intlike_struct }
241308
sil_moveonlydeinit MOSingleRefcountLikeStruct { @destroy_single_refcount_like_struct }
309+
sil_moveonlydeinit MOVeryBigStructDeinit { @destroy_big }
310+
sil_moveonlydeinit MOGenericDeinit { @destroy_generic }
242311

243312
// Check that destroy value witnesses invoke the deinit function, either
244313
// indirectly or directly.

test/Incremental/Verifier/multi-file-private/Inputs/Inner.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// expected-provides{{Inner}}
22
// expected-member{{main.Inner.init}}
3+
// expected-member{{main.Inner.deinit}}
34
public struct Inner {}
45

56
// expected-provides{{Foo}}

test/Incremental/Verifier/multi-file-private/Inputs/UsesInner.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@
66
public func blah(foo: Foo?) {
77
blah(foo: foo ?? defaultFoo)
88
}
9+
10+
11+
// expected-member {{Swift.Optional<Wrapped>.deinit}}
12+
// expected-member {{main.Inner.deinit}}

test/Incremental/Verifier/single-file-private/AnyObject.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,8 @@ func lookupOnAnyObject(object: AnyObject) { // expected-provides {{lookupOnAnyOb
108108
// expected-member {{ObjectiveC.NSObjectProtocol.someMethodWithUnavailableOptions}}
109109
// expected-member {{ObjectiveC.NSObjectProtocol.someMethodWithPotentiallyUnavailableOptions}}
110110
// expected-member {{ObjectiveC.NSObjectProtocol.someMethodWithDeprecatedOptions}}
111+
112+
// expected-member {{Swift.Optional<Wrapped>.deinit}}
113+
// expected-member {{Swift.Int32.deinit}}
114+
// expected-member {{Swift.Int.deinit}}
115+
// expected-member {{Swift.UnsafeMutablePointer<Pointee>.deinit}}

0 commit comments

Comments
 (0)