mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
687 lines
24 KiB
C++
687 lines
24 KiB
C++
//===--- Outlining.cpp - Outlining value operations -----------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements IR generation for outlined value operations in Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Outlining.h"
|
|
|
|
#include "Explosion.h"
|
|
#include "GenOpaque.h"
|
|
#include "GenProto.h"
|
|
#include "GenericRequirement.h"
|
|
#include "IRGenFunction.h"
|
|
#include "IRGenMangler.h"
|
|
#include "IRGenModule.h"
|
|
#include "LoadableTypeInfo.h"
|
|
#include "LocalTypeDataKind.h"
|
|
#include "MetadataRequest.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/IRGen/GenericRequirement.h"
|
|
#include "swift/IRGen/Linking.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
static GenericEnvironment *digOutGenericEnvironment(CanType loweredType) {
|
|
// Find a non-local, non-opaque archetype in the type and pull out
|
|
// its generic environment.
|
|
// TODO: we ought to be able to usefully minimize this
|
|
|
|
GenericEnvironment *env = nullptr;
|
|
loweredType.findIf([&env](CanType t) -> bool {
|
|
if (auto arch = dyn_cast<ArchetypeType>(t)) {
|
|
if (!isa<PrimaryArchetypeType>(arch) && !isa<PackArchetypeType>(arch))
|
|
return false;
|
|
env = arch->getGenericEnvironment();
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
return env;
|
|
}
|
|
|
|
OutliningMetadataCollector::OutliningMetadataCollector(
|
|
SILType T, IRGenFunction &IGF, LayoutIsNeeded_t needsLayout,
|
|
DeinitIsNeeded_t needsDeinitTypes)
|
|
: T(T), IGF(IGF), needsLayout(needsLayout), needsDeinit(needsDeinitTypes) {}
|
|
|
|
void OutliningMetadataCollector::collectTypeMetadata(SILType ty) {
|
|
assert(state != OutliningMetadataCollector::State::Kind::Collected);
|
|
// If the type has no archetypes, we can emit it from scratch in the callee.
|
|
if (!ty.hasArchetype()) {
|
|
return;
|
|
}
|
|
|
|
// Substitute opaque types if allowed.
|
|
ty = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(ty);
|
|
|
|
collectTypeMetadataForLayout(ty);
|
|
collectTypeMetadataForDeinit(ty);
|
|
}
|
|
|
|
void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType ty) {
|
|
if (!needsLayout)
|
|
return;
|
|
|
|
auto astType = ty.getASTType();
|
|
auto &ti = IGF.IGM.getTypeInfoForLowered(astType);
|
|
|
|
// 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
|
|
// non ABI accessible field/element types.
|
|
if (isa<FixedTypeInfo>(ti) || !ti.isABIAccessible()) {
|
|
return;
|
|
}
|
|
|
|
// 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 (astType->isLegalFormalType()) {
|
|
return state.getCollecting().addFormalTypeMetadata(astType);
|
|
}
|
|
|
|
state.getCollecting().addRepresentationTypeMetadata(ty);
|
|
}
|
|
|
|
void OutliningMetadataCollector::collectTypeMetadataForDeinit(SILType ty) {
|
|
if (!needsDeinit)
|
|
return;
|
|
|
|
auto *nominal = ty.getASTType()->getAnyNominal();
|
|
if (!nominal)
|
|
return;
|
|
if (!nominal->getValueTypeDestructor())
|
|
return;
|
|
assert(ty.isMoveOnly());
|
|
|
|
state.getCollecting().addValueTypeWithDeinit(ty);
|
|
}
|
|
|
|
void OutliningMetadataCollector::materializeFormalTypeMetadata(
|
|
CanType ty, State::Collected::Elements &into) {
|
|
// If the type has no archetypes, we can emit it from scratch in the callee.
|
|
assert(ty->hasArchetype());
|
|
|
|
auto key = LocalTypeDataKey(ty, LocalTypeDataKind::forFormalTypeMetadata());
|
|
if (into.Values.count(key))
|
|
return;
|
|
|
|
auto metadata = IGF.emitTypeMetadataRef(ty);
|
|
into.Values.insert({key, metadata});
|
|
|
|
assert(into.Values.count(key));
|
|
}
|
|
|
|
void OutliningMetadataCollector::materializeRepresentationTypeMetadata(
|
|
SILType ty, State::Collected::Elements &into) {
|
|
auto key = LocalTypeDataKey(
|
|
ty.getASTType(), LocalTypeDataKind::forRepresentationTypeMetadata());
|
|
if (into.Values.count(key))
|
|
return;
|
|
|
|
auto metadata = IGF.emitTypeMetadataRefForLayout(ty);
|
|
into.Values.insert({key, metadata});
|
|
}
|
|
|
|
void OutliningMetadataCollector::materialize() {
|
|
if (state == State::Kind::Collected)
|
|
return;
|
|
|
|
auto collection = std::move(state.getCollecting());
|
|
switch (collection) {
|
|
case State::CollectionKind::Elements: {
|
|
auto &elements = collection.getElements();
|
|
auto &collected = state.setCollectedElements();
|
|
for (auto &element : elements.elements) {
|
|
switch (element) {
|
|
case State::ElementKind::MetadataForFormal: {
|
|
auto ty = element.getFormalType();
|
|
materializeFormalTypeMetadata(ty, /*into=*/collected);
|
|
break;
|
|
}
|
|
case State::ElementKind::MetadataForRepresentation: {
|
|
auto ty = element.getRepresentationType();
|
|
materializeRepresentationTypeMetadata(ty, /*into=*/collected);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case State::CollectionKind::Environment: {
|
|
auto pair = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto sig = pair.second;
|
|
auto subs = digOutGenericEnvironment(T.getASTType())
|
|
->getForwardingSubstitutionMap();
|
|
auto &collected = state.setCollectedEnvironment(subs);
|
|
|
|
GenericTypeRequirements requirements(IGF.IGM, sig);
|
|
for (auto requirement : requirements.getRequirements()) {
|
|
auto *value = emitGenericRequirementFromSubstitutions(
|
|
IGF, requirement, MetadataState::Complete, subs);
|
|
collected.Requirements.insert({requirement, value});
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OutliningMetadataCollector::addPolymorphicArguments(
|
|
SmallVectorImpl<llvm::Value *> &args) const {
|
|
assert(hasFinished());
|
|
if (state == State::Kind::Empty)
|
|
return;
|
|
auto &collected = state.getCollected();
|
|
switch (collected) {
|
|
case State::CollectionKind::Elements: {
|
|
for (auto &pair : collected.getElements().Values) {
|
|
auto metadata = pair.second;
|
|
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
|
|
args.push_back(metadata);
|
|
}
|
|
return;
|
|
}
|
|
case State::CollectionKind::Environment: {
|
|
for (auto &pair : collected.getEnvironment().Requirements) {
|
|
auto *value = pair.second;
|
|
args.push_back(value);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OutliningMetadataCollector::addPolymorphicParameterTypes(
|
|
SmallVectorImpl<llvm::Type *> ¶mTys) const {
|
|
assert(hasFinished());
|
|
if (state == State::Kind::Empty)
|
|
return;
|
|
auto &collected = state.getCollected();
|
|
switch (collected) {
|
|
case State::CollectionKind::Elements: {
|
|
for (auto &pair : collected.getElements().Values) {
|
|
auto *metadata = pair.second;
|
|
paramTys.push_back(metadata->getType());
|
|
}
|
|
return;
|
|
}
|
|
case State::CollectionKind::Environment: {
|
|
for (auto &pair : collected.getEnvironment().Requirements) {
|
|
auto *value = pair.second;
|
|
paramTys.push_back(value->getType());
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OutliningMetadataCollector::bindPolymorphicParameters(
|
|
IRGenFunction &IGF, Explosion ¶ms) const {
|
|
assert(hasFinished());
|
|
if (state == State::Kind::Empty)
|
|
return;
|
|
auto &collected = state.getCollected();
|
|
switch (collected) {
|
|
case State::CollectionKind::Elements: {
|
|
// Note that our parameter IGF intentionally shadows the IGF that this
|
|
// collector was built with.
|
|
for (auto &pair : collected.getElements().Values) {
|
|
llvm::Value *arg = params.claimNext();
|
|
|
|
auto key = pair.first;
|
|
assert(key.Kind.isAnyTypeMetadata());
|
|
setTypeMetadataName(IGF.IGM, arg, key.Type);
|
|
if (key.Kind == LocalTypeDataKind::forRepresentationTypeMetadata()) {
|
|
IGF.setUnscopedLocalTypeData(key, MetadataResponse::forComplete(arg));
|
|
} else {
|
|
IGF.bindLocalTypeDataFromTypeMetadata(key.Type,
|
|
IsExact,
|
|
arg,
|
|
MetadataState::Complete);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case State::CollectionKind::Environment: {
|
|
auto &environment = collected.getEnvironment();
|
|
for (auto &pair : environment.Requirements) {
|
|
bindGenericRequirement(IGF, pair.first, params.claimNext(),
|
|
MetadataState::Complete, environment.Subs);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::pair<CanType, CanGenericSignature>
|
|
irgen::getTypeAndGenericSignatureForManglingOutlineFunction(SILType type) {
|
|
auto loweredType = type.getASTType();
|
|
if (!loweredType->hasArchetype()) return {loweredType, nullptr};
|
|
|
|
GenericEnvironment *env = digOutGenericEnvironment(loweredType);
|
|
|
|
assert(env && "has archetype but no archetype?!");
|
|
return {loweredType->mapTypeOutOfContext()->getCanonicalType(),
|
|
env->getGenericSignature().getCanonicalSignature()};
|
|
}
|
|
|
|
bool TypeInfo::withWitnessableMetadataCollector(
|
|
IRGenFunction &IGF, SILType T, LayoutIsNeeded_t mayNeedLayout,
|
|
DeinitIsNeeded_t needsDeinit,
|
|
llvm::function_ref<void(OutliningMetadataCollector &)> invocation) const {
|
|
bool needsCollector = false;
|
|
LayoutIsNeeded_t needsLayout = LayoutIsNotNeeded;
|
|
if (!T.hasLocalArchetype() &&
|
|
!IGF.outliningCanCallValueWitnesses()) {
|
|
needsCollector = true;
|
|
if (T.hasArchetype()) {
|
|
needsLayout = LayoutIsNeeded;
|
|
}
|
|
} else if (!T.hasArchetype()) {
|
|
needsCollector = true;
|
|
// The implementation will call vwt in this case.
|
|
needsLayout = LayoutIsNotNeeded;
|
|
}
|
|
|
|
if (needsCollector) {
|
|
OutliningMetadataCollector collector(T, IGF, needsLayout, needsDeinit);
|
|
if (needsDeinit || needsLayout) {
|
|
// Only collect if anything would be collected.
|
|
collectMetadataForOutlining(collector, T);
|
|
}
|
|
collector.materialize();
|
|
invocation(collector);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TypeInfo::callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
|
|
SILType T, IsInitialization_t isInit,
|
|
IsTake_t isTake) const {
|
|
if (withWitnessableMetadataCollector(
|
|
IGF, T, LayoutIsNeeded, DeinitIsNotNeeded, [&](auto collector) {
|
|
collector.emitCallToOutlinedCopy(dest, src, T, *this, isInit,
|
|
isTake);
|
|
})) {
|
|
return;
|
|
}
|
|
|
|
if (isInit == IsInitialization && isTake == IsTake) {
|
|
return emitInitializeWithTakeCall(IGF, T, dest, src);
|
|
} else if (isInit == IsInitialization && isTake == IsNotTake) {
|
|
return emitInitializeWithCopyCall(IGF, T, dest, src);
|
|
} else if (isInit == IsNotInitialization && isTake == IsTake) {
|
|
return emitAssignWithTakeCall(IGF, T, dest, src);
|
|
} else if (isInit == IsNotInitialization && isTake == IsNotTake) {
|
|
return emitAssignWithCopyCall(IGF, T, dest, src);
|
|
}
|
|
llvm_unreachable("unknown case");
|
|
}
|
|
|
|
void OutliningMetadataCollector::emitCallToOutlinedCopy(
|
|
Address dest, Address src, SILType T, const TypeInfo &ti,
|
|
IsInitialization_t isInit, IsTake_t isTake) const {
|
|
assert(hasFinished());
|
|
assert(!needsDeinit);
|
|
llvm::SmallVector<llvm::Value *, 4> args;
|
|
args.push_back(IGF.Builder.CreateElementBitCast(src, ti.getStorageType())
|
|
.getAddress());
|
|
args.push_back(IGF.Builder.CreateElementBitCast(dest, ti.getStorageType())
|
|
.getAddress());
|
|
addPolymorphicArguments(args);
|
|
|
|
llvm::Constant *outlinedFn;
|
|
if (isInit && isTake) {
|
|
outlinedFn =
|
|
IGF.IGM.getOrCreateOutlinedInitializeWithTakeFunction(T, ti, *this);
|
|
} else if (isInit) {
|
|
outlinedFn =
|
|
IGF.IGM.getOrCreateOutlinedInitializeWithCopyFunction(T, ti, *this);
|
|
} else if (isTake) {
|
|
outlinedFn =
|
|
IGF.IGM.getOrCreateOutlinedAssignWithTakeFunction(T, ti, *this);
|
|
} else {
|
|
outlinedFn =
|
|
IGF.IGM.getOrCreateOutlinedAssignWithCopyFunction(T, ti, *this);
|
|
}
|
|
|
|
llvm::CallInst *call = IGF.Builder.CreateCall(
|
|
cast<llvm::Function>(outlinedFn)->getFunctionType(), outlinedFn, args);
|
|
call->setCallingConv(IGF.IGM.DefaultCC);
|
|
}
|
|
|
|
static bool needsSpecialOwnershipHandling(SILType t) {
|
|
auto astType = t.getASTType();
|
|
auto ref = dyn_cast<ReferenceStorageType>(astType);
|
|
if (!ref) {
|
|
return false;
|
|
}
|
|
return ref->getOwnership() != ReferenceOwnership::Strong;
|
|
}
|
|
|
|
static bool canUseValueWitnessForValueOp(IRGenModule &IGM, SILType T) {
|
|
if (!IGM.getSILModule().isTypeMetadataForLayoutAccessible(T))
|
|
return false;
|
|
|
|
// No value witness tables in embedded Swift.
|
|
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded))
|
|
return false;
|
|
|
|
// It is not a good code size trade-off to instantiate a metatype for
|
|
// existentials, and also does not back-deploy gracefully in the case of
|
|
// constrained protocols.
|
|
if (T.getASTType()->isExistentialType())
|
|
return false;
|
|
|
|
if (needsSpecialOwnershipHandling(T))
|
|
return false;
|
|
if (T.getASTType()->hasDynamicSelfType())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedInitializeWithTakeFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector) {
|
|
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto funcName =
|
|
IRGenMangler(T.getASTContext()).mangleOutlinedInitializeWithTakeFunction(manglingBits.first,
|
|
manglingBits.second, collector.IGF.isPerformanceConstraint);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.outliningCanCallValueWitnesses() ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.initializeWithTake(IGF, dest, src, T, true, /*zeroizeIfSensitive=*/ true);
|
|
} else {
|
|
emitInitializeWithTakeCall(IGF, T, dest, src);
|
|
}
|
|
});
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedInitializeWithCopyFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector) {
|
|
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto funcName =
|
|
IRGenMangler(T.getASTContext()).mangleOutlinedInitializeWithCopyFunction(manglingBits.first,
|
|
manglingBits.second, collector.IGF.isPerformanceConstraint);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.outliningCanCallValueWitnesses() ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.initializeWithCopy(IGF, dest, src, T, true);
|
|
} else {
|
|
emitInitializeWithCopyCall(IGF, T, dest, src);
|
|
}
|
|
});
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedAssignWithTakeFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector) {
|
|
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto funcName =
|
|
IRGenMangler(T.getASTContext()).mangleOutlinedAssignWithTakeFunction(manglingBits.first,
|
|
manglingBits.second, collector.IGF.isPerformanceConstraint);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.outliningCanCallValueWitnesses() ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.assignWithTake(IGF, dest, src, T, true);
|
|
} else {
|
|
emitAssignWithTakeCall(IGF, T, dest, src);
|
|
}
|
|
});
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedAssignWithCopyFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector) {
|
|
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto funcName =
|
|
IRGenMangler(T.getASTContext()).mangleOutlinedAssignWithCopyFunction(manglingBits.first,
|
|
manglingBits.second, collector.IGF.isPerformanceConstraint);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.outliningCanCallValueWitnesses() ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.assignWithCopy(IGF, dest, src, T, true);
|
|
} else {
|
|
emitAssignWithCopyCall(IGF, T, dest, src);
|
|
}
|
|
});
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedCopyAddrHelperFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector,
|
|
StringRef funcName,
|
|
CopyAddrHelperGenerator generator) {
|
|
assert(collector.hasFinished());
|
|
|
|
llvm::SmallVector<llvm::Type *, 4> paramTys;
|
|
paramTys.push_back(PtrTy);
|
|
paramTys.push_back(PtrTy);
|
|
collector.addPolymorphicParameterTypes(paramTys);
|
|
|
|
IRLinkage *linkage = nullptr;
|
|
IRLinkage privateLinkage = {
|
|
llvm::GlobalValue::PrivateLinkage,
|
|
llvm::GlobalValue::DefaultVisibility,
|
|
llvm::GlobalValue::DefaultStorageClass,
|
|
};
|
|
|
|
// Opaque result types might lead to different expansions in different files.
|
|
// The default hidden linkonce_odr might lead to linking an implementation
|
|
// from another file that head a different expansion/different
|
|
// signature/different implementation.
|
|
if (getTypeProperties(T, TypeExpansionContext::minimal())
|
|
.isTypeExpansionSensitive()) {
|
|
linkage = &privateLinkage;
|
|
}
|
|
|
|
return getOrCreateHelperFunction(
|
|
funcName, PtrTy, paramTys,
|
|
[&](IRGenFunction &IGF) {
|
|
auto params = IGF.collectParameters();
|
|
Address src = ti.getAddressForPointer(params.claimNext());
|
|
Address dest = ti.getAddressForPointer(params.claimNext());
|
|
collector.bindPolymorphicParameters(IGF, params);
|
|
generator(IGF, dest, src, T, ti);
|
|
IGF.Builder.CreateRet(dest.getAddress());
|
|
},
|
|
true /*setIsNoInline*/,
|
|
false /*forPrologue*/,
|
|
collector.IGF.isPerformanceConstraint,
|
|
linkage);
|
|
}
|
|
|
|
void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
|
|
Address addr, SILType T) const {
|
|
// Short-cut destruction of trivial values.
|
|
if (IGF.IGM.getTypeProperties(T).isTrivial())
|
|
return;
|
|
|
|
if (withWitnessableMetadataCollector(
|
|
IGF, T, LayoutIsNeeded, DeinitIsNeeded, [&](auto collector) {
|
|
collector.emitCallToOutlinedDestroy(addr, T, *this);
|
|
})) {
|
|
return;
|
|
}
|
|
|
|
return emitDestroyCall(IGF, T, addr);
|
|
}
|
|
|
|
void OutliningMetadataCollector::emitCallToOutlinedDestroy(
|
|
Address addr, SILType T, const TypeInfo &ti) const {
|
|
assert(hasFinished());
|
|
assert(needsDeinit);
|
|
llvm::SmallVector<llvm::Value *, 4> args;
|
|
args.push_back(IGF.Builder.CreateElementBitCast(addr, ti.getStorageType())
|
|
.getAddress());
|
|
addPolymorphicArguments(args);
|
|
|
|
auto outlinedFn =
|
|
IGF.IGM.getOrCreateOutlinedDestroyFunction(T, ti, *this);
|
|
|
|
llvm::CallInst *call = IGF.Builder.CreateCall(
|
|
cast<llvm::Function>(outlinedFn)->getFunctionType(), outlinedFn, args);
|
|
call->setCallingConv(IGF.IGM.DefaultCC);
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector) {
|
|
IRGenMangler mangler(T.getASTContext());
|
|
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto funcName = mangler.mangleOutlinedDestroyFunction(manglingBits.first,
|
|
manglingBits.second, collector.IGF.isPerformanceConstraint);
|
|
|
|
IRLinkage *linkage = nullptr;
|
|
IRLinkage privateLinkage = {
|
|
llvm::GlobalValue::PrivateLinkage,
|
|
llvm::GlobalValue::DefaultVisibility,
|
|
llvm::GlobalValue::DefaultStorageClass,
|
|
};
|
|
|
|
// Opaque result types might lead to different expansions in different files.
|
|
// The default hidden linkonce_odr might lead to linking an implementation
|
|
// from another file that head a different expansion/different
|
|
// signature/different implementation.
|
|
if (getTypeProperties(T, TypeExpansionContext::minimal())
|
|
.isTypeExpansionSensitive()) {
|
|
linkage = &privateLinkage;
|
|
}
|
|
|
|
llvm::SmallVector<llvm::Type *, 4> paramTys;
|
|
paramTys.push_back(PtrTy);
|
|
collector.addPolymorphicParameterTypes(paramTys);
|
|
|
|
return getOrCreateHelperFunction(
|
|
funcName, PtrTy, paramTys,
|
|
[&](IRGenFunction &IGF) {
|
|
Explosion params = IGF.collectParameters();
|
|
Address addr = ti.getAddressForPointer(params.claimNext());
|
|
collector.bindPolymorphicParameters(IGF, params);
|
|
if (!IGF.outliningCanCallValueWitnesses() ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.destroy(IGF, addr, T, true);
|
|
} else {
|
|
emitDestroyCall(IGF, T, addr);
|
|
}
|
|
|
|
IGF.Builder.CreateRet(addr.getAddress());
|
|
},
|
|
true /*setIsNoInline*/,
|
|
false /*forPrologue*/,
|
|
collector.IGF.isPerformanceConstraint,
|
|
linkage);
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti,
|
|
SILType t,
|
|
llvm::Type *llvmType,
|
|
Atomicity atomicity) {
|
|
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
|
|
IRGenMangler mangler(t.getASTContext());
|
|
auto manglingBits =
|
|
getTypeAndGenericSignatureForManglingOutlineFunction(t);
|
|
auto funcName = mangler.mangleOutlinedRetainFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
llvm::Type *argTys[] = {llvmType};
|
|
return getOrCreateHelperFunction(
|
|
funcName, llvmType, argTys,
|
|
[&](IRGenFunction &IGF) {
|
|
auto it = IGF.CurFn->arg_begin();
|
|
Address addr(&*it++, loadableTI->getStorageType(),
|
|
loadableTI->getFixedAlignment());
|
|
Explosion loaded;
|
|
loadableTI->loadAsTake(IGF, addr, loaded);
|
|
Explosion out;
|
|
loadableTI->copy(IGF, loaded, out, atomicity);
|
|
(void)out.claimAll();
|
|
IGF.Builder.CreateRet(addr.getAddress());
|
|
},
|
|
true /*setIsNoInline*/);
|
|
}
|
|
|
|
void TypeInfo::callOutlinedRelease(IRGenFunction &IGF, Address addr, SILType T,
|
|
Atomicity atomicity) const {
|
|
OutliningMetadataCollector collector(T, IGF, LayoutIsNotNeeded,
|
|
DeinitIsNeeded);
|
|
collectMetadataForOutlining(collector, T);
|
|
collector.materialize();
|
|
collector.emitCallToOutlinedRelease(addr, T, *this, atomicity);
|
|
}
|
|
|
|
void OutliningMetadataCollector::emitCallToOutlinedRelease(
|
|
Address addr, SILType T, const TypeInfo &ti, Atomicity atomicity) const {
|
|
assert(hasFinished());
|
|
assert(!needsLayout);
|
|
assert(needsDeinit);
|
|
llvm::SmallVector<llvm::Value *, 4> args;
|
|
args.push_back(addr.getAddress());
|
|
addPolymorphicArguments(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(t.getASTContext());
|
|
auto manglingBits =
|
|
getTypeAndGenericSignatureForManglingOutlineFunction(t);
|
|
auto funcName = mangler.mangleOutlinedReleaseFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
llvm::SmallVector<llvm::Type *, 4> argTys;
|
|
argTys.push_back(ptrTy);
|
|
collector.addPolymorphicParameterTypes(argTys);
|
|
return getOrCreateHelperFunction(
|
|
funcName, ptrTy, argTys,
|
|
[&](IRGenFunction &IGF) {
|
|
Explosion params = IGF.collectParameters();
|
|
Address addr(params.claimNext(), loadableTI->getStorageType(),
|
|
loadableTI->getFixedAlignment());
|
|
collector.bindPolymorphicParameters(IGF, params);
|
|
Explosion loaded;
|
|
loadableTI->loadAsTake(IGF, addr, loaded);
|
|
loadableTI->consume(IGF, loaded, atomicity, t);
|
|
IGF.Builder.CreateRet(addr.getAddress());
|
|
},
|
|
true /*setIsNoInline*/);
|
|
}
|