Skip to content

[IRGen] Outlined value functions that destroy move-only-with-deinit types take and forward those types' metadata. #71799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions lib/IRGen/GenExistential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ namespace {
asDerived().emitValueAssignWithCopy(IGF, destValue, srcValue);
emitCopyOfTables(IGF, dest, src);
} else {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
collector.emitCallToOutlinedCopy(dest, src, T, *this,
IsNotInitialization, IsNotTake);
}
Expand All @@ -267,7 +268,8 @@ namespace {
asDerived().emitValueInitializeWithCopy(IGF, destValue, srcValue);
emitCopyOfTables(IGF, dest, src);
} else {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
collector.emitCallToOutlinedCopy(dest, src, T, *this,
IsInitialization, IsNotTake);
}
Expand All @@ -281,7 +283,8 @@ namespace {
asDerived().emitValueAssignWithTake(IGF, destValue, srcValue);
emitCopyOfTables(IGF, dest, src);
} else {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
collector.emitCallToOutlinedCopy(dest, src, T, *this,
IsNotInitialization, IsTake);
}
Expand All @@ -295,7 +298,8 @@ namespace {
asDerived().emitValueInitializeWithTake(IGF, destValue, srcValue);
emitCopyOfTables(IGF, dest, src);
} else {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
collector.emitCallToOutlinedCopy(dest, src, T, *this,
IsInitialization, IsTake);
}
Expand All @@ -307,7 +311,8 @@ namespace {
Address valueAddr = projectValue(IGF, existential);
asDerived().emitValueDestroy(IGF, valueAddr);
} else {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNeeded);
collector.emitCallToOutlinedDestroy(existential, T, *this);
}
}
Expand Down Expand Up @@ -963,7 +968,8 @@ class OpaqueExistentialTypeInfo final :
srcBuffer);
} else {
// Create an outlined function to avoid explosion
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
collector.emitCallToOutlinedCopy(dest, src, T, *this,
IsInitialization, IsNotTake);
}
Expand All @@ -979,7 +985,8 @@ class OpaqueExistentialTypeInfo final :
IGF.emitMemCpy(dest, src, getLayout().getSize(IGF.IGM));
} else {
// Create an outlined function to avoid explosion
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
collector.emitCallToOutlinedCopy(dest, src, T, *this,
IsInitialization, IsTake);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ void LoadableTypeInfo::initializeWithCopy(IRGenFunction &IGF, Address destAddr,
loadAsCopy(IGF, srcAddr, copy);
initialize(IGF, copy, destAddr, true);
} else {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, LayoutIsNeeded,
DeinitIsNotNeeded);
// No need to collect anything because we assume loadable types can be
// loaded without enums.
collector.emitCallToOutlinedCopy(
Expand Down
6 changes: 4 additions & 2 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1193,8 +1193,10 @@ class IRGenModule {
llvm::Constant *getOrCreateRetainFunction(const TypeInfo &objectTI, SILType t,
llvm::Type *llvmType, Atomicity atomicity);

llvm::Constant *getOrCreateReleaseFunction(const TypeInfo &objectTI, SILType t,
llvm::Type *llvmType, Atomicity atomicity);
llvm::Constant *
getOrCreateReleaseFunction(const TypeInfo &objectTI, SILType t,
llvm::Type *llvmType, Atomicity atomicity,
const OutliningMetadataCollector &collector);

llvm::Constant *getOrCreateOutlinedInitializeWithTakeFunction(
SILType objectType, const TypeInfo &objectTI,
Expand Down
8 changes: 1 addition & 7 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5098,15 +5098,9 @@ void IRGenSILFunction::visitReleaseValueAddrInst(
if (tryEmitDestroyUsingDeinit(*this, addr, addrTy)) {
return;
}
llvm::Type *llvmType = addr.getAddress()->getType();
const TypeInfo &addrTI = getTypeInfo(addrTy);
auto atomicity = i->isAtomic() ? Atomicity::Atomic : Atomicity::NonAtomic;
auto *outlinedF = cast<llvm::Function>(
IGM.getOrCreateReleaseFunction(addrTI, objectT, llvmType, atomicity));
llvm::Value *args[] = {addr.getAddress()};
llvm::CallInst *call =
Builder.CreateCall(outlinedF->getFunctionType(), outlinedF, args);
call->setCallingConv(IGM.DefaultCC);
addrTI.callOutlinedRelease(*this, addr, objectT, atomicity);
}

void IRGenSILFunction::visitDestroyValueInst(swift::DestroyValueInst *i) {
Expand Down
109 changes: 77 additions & 32 deletions lib/IRGen/Outlining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,29 @@
using namespace swift;
using namespace irgen;

void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) {
void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType ty) {
// If the type has no archetypes, we can emit it from scratch in the callee.
if (!type.hasArchetype()) {
if (!ty.hasArchetype()) {
return;
}

// Substitute opaque types if allowed.
type =
IGF.IGM.substOpaqueTypesWithUnderlyingTypes(type, CanGenericSignature());
ty = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(ty, CanGenericSignature());

auto formalType = type.getASTType();
auto &ti = IGF.IGM.getTypeInfoForLowered(formalType);
auto astType = ty.getASTType();
auto &ti = IGF.IGM.getTypeInfoForLowered(astType);

if (needsDeinit) {
auto *nominal = ty.getASTType()->getAnyNominal();
if (nominal && nominal->getValueTypeDestructor()) {
assert(ty.isMoveOnly());
collectFormalTypeMetadata(ty.getASTType());
}
}

if (!needsLayout) {
return;
}

// We don't need the metadata for fixed size types or types that are not ABI
// accessible. Outlining will call the value witness of the enclosing type of
Expand All @@ -55,16 +66,11 @@ void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) {
// If the type is a legal formal type, add it as a formal type.
// FIXME: does this force us to emit a more expensive metadata than we need
// to?
if (formalType->isLegalFormalType()) {
return collectFormalTypeMetadata(formalType);
if (astType->isLegalFormalType()) {
return collectFormalTypeMetadata(astType);
}

auto key = LocalTypeDataKey(type.getASTType(),
LocalTypeDataKind::forRepresentationTypeMetadata());
if (Values.count(key)) return;

auto metadata = IGF.emitTypeMetadataRefForLayout(type);
Values.insert({key, metadata});
collectRepresentationTypeMetadata(ty);
}

void OutliningMetadataCollector::collectFormalTypeMetadata(CanType type) {
Expand All @@ -78,6 +84,15 @@ void OutliningMetadataCollector::collectFormalTypeMetadata(CanType type) {
Values.insert({key, metadata});
}

void OutliningMetadataCollector::collectRepresentationTypeMetadata(SILType ty) {
auto key = LocalTypeDataKey(
ty.getASTType(), LocalTypeDataKind::forRepresentationTypeMetadata());
if (Values.count(key))
return;

auto metadata = IGF.emitTypeMetadataRefForLayout(ty);
Values.insert({key, metadata});
}

void OutliningMetadataCollector::addMetadataArguments(
SmallVectorImpl<llvm::Value*> &args) const {
Expand Down Expand Up @@ -136,11 +151,12 @@ irgen::getTypeAndGenericSignatureForManglingOutlineFunction(SILType type) {
}

bool TypeInfo::withMetadataCollector(
IRGenFunction &IGF, SILType T,
IRGenFunction &IGF, SILType T, LayoutIsNeeded_t needsLayout,
DeinitIsNeeded_t needsDeinit,
llvm::function_ref<void(OutliningMetadataCollector &)> invocation) const {
if (!T.hasLocalArchetype() &&
!IGF.outliningCanCallValueWitnesses()) {
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, needsLayout, needsDeinit);
if (T.hasArchetype()) {
collectMetadataForOutlining(collector, T);
}
Expand All @@ -150,7 +166,7 @@ bool TypeInfo::withMetadataCollector(

if (!T.hasArchetype()) {
// The implementation will call vwt in this case.
OutliningMetadataCollector collector(IGF);
OutliningMetadataCollector collector(IGF, needsLayout, needsDeinit);
invocation(collector);
return true;
}
Expand All @@ -161,9 +177,11 @@ bool TypeInfo::withMetadataCollector(
void TypeInfo::callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, IsInitialization_t isInit,
IsTake_t isTake) const {
if (withMetadataCollector(IGF, T, [&](auto collector) {
collector.emitCallToOutlinedCopy(dest, src, T, *this, isInit, isTake);
})) {
if (withMetadataCollector(IGF, T, LayoutIsNeeded, DeinitIsNotNeeded,
[&](auto collector) {
collector.emitCallToOutlinedCopy(
dest, src, T, *this, isInit, isTake);
})) {
return;
}

Expand All @@ -183,6 +201,8 @@ void OutliningMetadataCollector::emitCallToOutlinedCopy(
Address dest, Address src,
SILType T, const TypeInfo &ti,
IsInitialization_t isInit, IsTake_t isTake) const {
assert(needsLayout);
assert(!needsDeinit);
llvm::SmallVector<llvm::Value *, 4> args;
args.push_back(IGF.Builder.CreateElementBitCast(src, ti.getStorageType())
.getAddress());
Expand Down Expand Up @@ -356,9 +376,10 @@ void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
if (IGF.IGM.getTypeLowering(T).isTrivial())
return;

if (withMetadataCollector(IGF, T, [&](auto collector) {
collector.emitCallToOutlinedDestroy(addr, T, *this);
})) {
if (withMetadataCollector(
IGF, T, LayoutIsNeeded, DeinitIsNeeded, [&](auto collector) {
collector.emitCallToOutlinedDestroy(addr, T, *this);
})) {
return;
}

Expand All @@ -367,6 +388,8 @@ void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,

void OutliningMetadataCollector::emitCallToOutlinedDestroy(
Address addr, SILType T, const TypeInfo &ti) const {
assert(needsLayout);
assert(needsDeinit);
llvm::SmallVector<llvm::Value *, 4> args;
args.push_back(IGF.Builder.CreateElementBitCast(addr, ti.getStorageType())
.getAddress());
Expand Down Expand Up @@ -439,24 +462,46 @@ llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti,
true /*setIsNoInline*/);
}

llvm::Constant *
IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti,
SILType t,
llvm::Type *llvmType,
Atomicity atomicity) {
void TypeInfo::callOutlinedRelease(IRGenFunction &IGF, Address addr, SILType T,
Atomicity atomicity) const {
OutliningMetadataCollector collector(IGF, LayoutIsNotNeeded, DeinitIsNeeded);
collectMetadataForOutlining(collector, T);
collector.emitCallToOutlinedRelease(addr, T, *this, atomicity);
}

void OutliningMetadataCollector::emitCallToOutlinedRelease(
Address addr, SILType T, const TypeInfo &ti, Atomicity atomicity) const {
assert(!needsLayout);
assert(needsDeinit);
llvm::SmallVector<llvm::Value *, 4> args;
args.push_back(addr.getAddress());
addMetadataArguments(args);
auto *outlinedF = cast<llvm::Function>(IGF.IGM.getOrCreateReleaseFunction(
ti, T, addr.getAddress()->getType(), atomicity, *this));
llvm::CallInst *call =
IGF.Builder.CreateCall(outlinedF->getFunctionType(), outlinedF, args);
call->setCallingConv(IGF.IGM.DefaultCC);
}

llvm::Constant *IRGenModule::getOrCreateReleaseFunction(
const TypeInfo &ti, SILType t, llvm::Type *ptrTy, Atomicity atomicity,
const OutliningMetadataCollector &collector) {
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
IRGenMangler mangler;
auto manglingBits =
getTypeAndGenericSignatureForManglingOutlineFunction(t);
auto funcName = mangler.mangleOutlinedReleaseFunction(manglingBits.first,
manglingBits.second);
llvm::Type *argTys[] = {llvmType};
llvm::SmallVector<llvm::Type *, 4> argTys;
argTys.push_back(ptrTy);
collector.addMetadataParameterTypes(argTys);
return getOrCreateHelperFunction(
funcName, llvmType, argTys,
funcName, ptrTy, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
Address addr(&*it++, loadableTI->getStorageType(),
Explosion params = IGF.collectParameters();
Address addr(params.claimNext(), loadableTI->getStorageType(),
loadableTI->getFixedAlignment());
collector.bindMetadataParameters(IGF, params);
Explosion loaded;
loadableTI->loadAsTake(IGF, addr, loaded);
loadableTI->consume(IGF, loaded, atomicity, t);
Expand Down
25 changes: 22 additions & 3 deletions lib/IRGen/Outlining.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#ifndef SWIFT_IRGEN_OUTLINING_H
#define SWIFT_IRGEN_OUTLINING_H

#include "IRGen.h"
#include "LocalTypeDataKind.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/MapVector.h"
#include "LocalTypeDataKind.h"

namespace llvm {
class Value;
Expand All @@ -41,6 +41,16 @@ class IRGenFunction;
class IRGenModule;
class TypeInfo;

enum LayoutIsNeeded_t : bool {
LayoutIsNotNeeded = false,
LayoutIsNeeded = true
};

enum DeinitIsNeeded_t : bool {
DeinitIsNotNeeded = false,
DeinitIsNeeded = true
};

/// A helper class for emitting outlined value operations.
///
/// The use-pattern for this class is:
Expand All @@ -51,23 +61,32 @@ class TypeInfo;
class OutliningMetadataCollector {
public:
IRGenFunction &IGF;
const unsigned needsLayout : 1;
const unsigned needsDeinit : 1;

private:
llvm::MapVector<LocalTypeDataKey, llvm::Value *> Values;
friend class IRGenModule;

public:
OutliningMetadataCollector(IRGenFunction &IGF) : IGF(IGF) {}
OutliningMetadataCollector(IRGenFunction &IGF, LayoutIsNeeded_t needsLayout,
DeinitIsNeeded_t needsDeinitTypes)
: IGF(IGF), needsLayout(needsLayout), needsDeinit(needsDeinitTypes) {}

void collectFormalTypeMetadata(CanType type);
void collectTypeMetadataForLayout(SILType type);

void emitCallToOutlinedCopy(Address dest, Address src,
SILType T, const TypeInfo &ti,
IsInitialization_t isInit, IsTake_t isTake) const;
void emitCallToOutlinedDestroy(Address addr, SILType T,
const TypeInfo &ti) const;
void emitCallToOutlinedRelease(Address addr, SILType T, const TypeInfo &ti,
Atomicity atomicity) const;

private:
void collectFormalTypeMetadata(CanType type);
void collectRepresentationTypeMetadata(SILType ty);

void addMetadataArguments(SmallVectorImpl<llvm::Value *> &args) const ;
void addMetadataParameterTypes(SmallVectorImpl<llvm::Type *> &paramTys) const;
void bindMetadataParameters(IRGenFunction &helperIGF,
Expand Down
Loading