Skip to content

Commit 36b473d

Browse files
committed
[IRGen] Pass deinit metadata to outlined release.
Given a releasable value which contains a noncopyable value type with a deinit, that values outlined release function, among other things, must call the deinit of that noncopyable value type. In order to do that, its type metadata must be passed to the value function if it has an archetype.
1 parent f3b9dec commit 36b473d

File tree

4 files changed

+70
-15
lines changed

4 files changed

+70
-15
lines changed

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,8 +1193,10 @@ class IRGenModule {
11931193
llvm::Constant *getOrCreateRetainFunction(const TypeInfo &objectTI, SILType t,
11941194
llvm::Type *llvmType, Atomicity atomicity);
11951195

1196-
llvm::Constant *getOrCreateReleaseFunction(const TypeInfo &objectTI, SILType t,
1197-
llvm::Type *llvmType, Atomicity atomicity);
1196+
llvm::Constant *
1197+
getOrCreateReleaseFunction(const TypeInfo &objectTI, SILType t,
1198+
llvm::Type *llvmType, Atomicity atomicity,
1199+
const OutliningMetadataCollector &collector);
11981200

11991201
llvm::Constant *getOrCreateOutlinedInitializeWithTakeFunction(
12001202
SILType objectType, const TypeInfo &objectTI,

lib/IRGen/Outlining.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -464,33 +464,44 @@ llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti,
464464

465465
void TypeInfo::callOutlinedRelease(IRGenFunction &IGF, Address addr, SILType T,
466466
Atomicity atomicity) const {
467-
llvm::Type *llvmType = addr.getAddress()->getType();
468-
auto *outlinedF = cast<llvm::Function>(
469-
IGF.IGM.getOrCreateReleaseFunction(*this, T, llvmType, atomicity));
470-
llvm::Value *args[] = {addr.getAddress()};
467+
OutliningMetadataCollector collector(IGF, LayoutIsNotNeeded, DeinitIsNeeded);
468+
collectMetadataForOutlining(collector, T);
469+
collector.emitCallToOutlinedRelease(addr, T, *this, atomicity);
470+
}
471+
472+
void OutliningMetadataCollector::emitCallToOutlinedRelease(
473+
Address addr, SILType T, const TypeInfo &ti, Atomicity atomicity) const {
474+
assert(!needsLayout);
475+
assert(needsDeinit);
476+
llvm::SmallVector<llvm::Value *, 4> args;
477+
args.push_back(addr.getAddress());
478+
addMetadataArguments(args);
479+
auto *outlinedF = cast<llvm::Function>(IGF.IGM.getOrCreateReleaseFunction(
480+
ti, T, addr.getAddress()->getType(), atomicity, *this));
471481
llvm::CallInst *call =
472482
IGF.Builder.CreateCall(outlinedF->getFunctionType(), outlinedF, args);
473483
call->setCallingConv(IGF.IGM.DefaultCC);
474484
}
475485

476-
llvm::Constant *
477-
IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti,
478-
SILType t,
479-
llvm::Type *llvmType,
480-
Atomicity atomicity) {
486+
llvm::Constant *IRGenModule::getOrCreateReleaseFunction(
487+
const TypeInfo &ti, SILType t, llvm::Type *ptrTy, Atomicity atomicity,
488+
const OutliningMetadataCollector &collector) {
481489
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
482490
IRGenMangler mangler;
483491
auto manglingBits =
484492
getTypeAndGenericSignatureForManglingOutlineFunction(t);
485493
auto funcName = mangler.mangleOutlinedReleaseFunction(manglingBits.first,
486494
manglingBits.second);
487-
llvm::Type *argTys[] = {llvmType};
495+
llvm::SmallVector<llvm::Type *, 4> argTys;
496+
argTys.push_back(ptrTy);
497+
collector.addMetadataParameterTypes(argTys);
488498
return getOrCreateHelperFunction(
489-
funcName, llvmType, argTys,
499+
funcName, ptrTy, argTys,
490500
[&](IRGenFunction &IGF) {
491-
auto it = IGF.CurFn->arg_begin();
492-
Address addr(&*it++, loadableTI->getStorageType(),
501+
Explosion params = IGF.collectParameters();
502+
Address addr(params.claimNext(), loadableTI->getStorageType(),
493503
loadableTI->getFixedAlignment());
504+
collector.bindMetadataParameters(IGF, params);
494505
Explosion loaded;
495506
loadableTI->loadAsTake(IGF, addr, loaded);
496507
loadableTI->consume(IGF, loaded, atomicity, t);

lib/IRGen/Outlining.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef SWIFT_IRGEN_OUTLINING_H
1818
#define SWIFT_IRGEN_OUTLINING_H
1919

20+
#include "IRGen.h"
2021
#include "LocalTypeDataKind.h"
2122
#include "swift/Basic/LLVM.h"
2223
#include "llvm/ADT/MapVector.h"
@@ -79,6 +80,8 @@ class OutliningMetadataCollector {
7980
IsInitialization_t isInit, IsTake_t isTake) const;
8081
void emitCallToOutlinedDestroy(Address addr, SILType T,
8182
const TypeInfo &ti) const;
83+
void emitCallToOutlinedRelease(Address addr, SILType T, const TypeInfo &ti,
84+
Atomicity atomicity) const;
8285

8386
private:
8487
void collectFormalTypeMetadata(CanType type);

test/IRGen/moveonly_value_functions.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,45 @@ public func takeOuterDeinitingNC_1<T>(_ t: consuming OuterDeinitingNC_1<T>) {
8686
external_symbol()
8787
}
8888

89+
// If the destroyed value has no deinit, is releasable, and contains a
90+
// noncopyable value with a deinit, call the outlined release function.
91+
// Destroyed value:
92+
// - has NO deinit
93+
// - contains value type with deinit
94+
// - is releasable
95+
// On lifetime end:
96+
// - call outlined release function
97+
// CHECK-LABEL: define{{.*}} @"$s24moveonly_value_functions13takeOuterNC_1yyAA0eF2_1VyxGnlF"(
98+
// CHECK-SAME: ptr{{.*}} %0,
99+
// CHECK-SAME: ptr %T)
100+
// CHECK-SAME: {
101+
// CHECK: [[RESPONSE:%[^,]+]] = call{{.*}} @"$s24moveonly_value_functions26InnerDeinitingReleasableNCVMa"(
102+
// : i64 0,
103+
// CHECK-SAME: ptr %T)
104+
// CHECK: [[INNER_DEINITING_RELEASABLE_NC_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[RESPONSE]]
105+
// CHECK: call{{.*}} @"$s24moveonly_value_functions9OuterNC_1VyxGlWOs"(
106+
// CHECK-SAME: ptr %0,
107+
// CHECK-SAME: ptr [[INNER_DEINITING_RELEASABLE_NC_METADATA]])
108+
// CHECK: }
109+
110+
// Verify that the outlined release function takes the metadata for the
111+
// move-only-with-deinit type InnerDeinitingReleasableNC<T> and passes it along
112+
// to that deinit.
113+
// $s24moveonly_value_functions9OuterNC_1VyxGlWOs ---> outlined release of moveonly_value_functions.OuterNC_2<A>
114+
// CHECK-LABEL: define{{.*}} @"$s24moveonly_value_functions9OuterNC_1VyxGlWOs"(
115+
// CHECK-SAME: ptr %0,
116+
// CHECK-SAME: ptr %"InnerDeinitingReleasableNC<T>")
117+
// CHECK-SAME: {
118+
// ...
119+
// ...
120+
// CHECK: call swiftcc void @"$s24moveonly_value_functions26InnerDeinitingReleasableNCVfD"(
121+
// CHECK-SAME: ptr %"InnerDeinitingReleasableNC<T>",
122+
// : ptr noalias nocapture swiftself dereferenceable(64) %deinit.arg)
123+
// CHECK: }
124+
public func takeOuterNC_1<T>(_ o: consuming OuterNC_1<T>) {
125+
external_symbol()
126+
}
127+
89128
// If the destroyed value has no deinit, is releasable, and contains a
90129
// noncopyable value with a deinit, call the outlined destroy function.
91130
// Destroyed value:

0 commit comments

Comments
 (0)