mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
444 lines
17 KiB
C++
444 lines
17 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 "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/SIL/SILModule.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) {
|
|
// If the type has no archetypes, we can emit it from scratch in the callee.
|
|
if (!type.hasArchetype()) {
|
|
return;
|
|
}
|
|
|
|
// Substitute opaque types if allowed.
|
|
auto origType = type;
|
|
type =
|
|
IGF.IGM.substOpaqueTypesWithUnderlyingTypes(type, CanGenericSignature());
|
|
|
|
auto formalType = type.getASTType();
|
|
auto &ti = IGF.IGM.getTypeInfoForLowered(formalType);
|
|
|
|
// 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 ((!origType.getASTType()->hasOpaqueArchetype() &&
|
|
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 (formalType->isLegalFormalType()) {
|
|
return collectFormalTypeMetadata(formalType);
|
|
}
|
|
|
|
auto key = LocalTypeDataKey(type.getASTType(),
|
|
LocalTypeDataKind::forRepresentationTypeMetadata());
|
|
if (Values.count(key)) return;
|
|
|
|
auto metadata = IGF.emitTypeMetadataRefForLayout(type);
|
|
Values.insert({key, metadata});
|
|
}
|
|
|
|
void OutliningMetadataCollector::collectFormalTypeMetadata(CanType type) {
|
|
// If the type has no archetypes, we can emit it from scratch in the callee.
|
|
assert(type->hasArchetype());
|
|
|
|
auto key = LocalTypeDataKey(type, LocalTypeDataKind::forFormalTypeMetadata());
|
|
if (Values.count(key)) return;
|
|
|
|
auto metadata = IGF.emitTypeMetadataRef(type);
|
|
Values.insert({key, metadata});
|
|
}
|
|
|
|
|
|
void OutliningMetadataCollector::addMetadataArguments(
|
|
SmallVectorImpl<llvm::Value*> &args) const {
|
|
for (auto &pair : Values) {
|
|
auto metadata = pair.second;
|
|
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
|
|
args.push_back(metadata);
|
|
}
|
|
}
|
|
|
|
void OutliningMetadataCollector::addMetadataParameterTypes(
|
|
SmallVectorImpl<llvm::Type*> ¶mTys) const {
|
|
for (auto &pair : Values) {
|
|
auto *metadata = pair.second;
|
|
paramTys.push_back(metadata->getType());
|
|
}
|
|
}
|
|
|
|
void OutliningMetadataCollector::bindMetadataParameters(IRGenFunction &IGF,
|
|
Explosion ¶ms) const {
|
|
// Note that our parameter IGF intentionally shadows the IGF that this
|
|
// collector was built with.
|
|
for (auto &pair : Values) {
|
|
llvm::Value *arg = params.claimNext();
|
|
|
|
auto key = pair.first;
|
|
assert(key.Kind.isAnyTypeMetadata());
|
|
setTypeMetadataName(IGF.IGM, arg, key.Type);
|
|
IGF.setUnscopedLocalTypeData(key, MetadataResponse::forComplete(arg));
|
|
}
|
|
}
|
|
|
|
std::pair<CanType, CanGenericSignature>
|
|
irgen::getTypeAndGenericSignatureForManglingOutlineFunction(SILType type) {
|
|
auto loweredType = type.getASTType();
|
|
if (loweredType->hasArchetype()) {
|
|
GenericEnvironment *env = nullptr;
|
|
loweredType.findIf([&env](Type t) -> bool {
|
|
if (auto arch = t->getAs<ArchetypeType>()) {
|
|
auto root = arch->getRoot();
|
|
if (!isa<PrimaryArchetypeType>(root))
|
|
return false;
|
|
env = root->getGenericEnvironment();
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
assert(env && "has archetype but no archetype?!");
|
|
return {loweredType->mapTypeOutOfContext()->getCanonicalType(),
|
|
env->getGenericSignature().getCanonicalSignature()};
|
|
}
|
|
return {loweredType, nullptr};
|
|
}
|
|
|
|
void TypeInfo::callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
|
|
SILType T, IsInitialization_t isInit,
|
|
IsTake_t isTake) const {
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling) {
|
|
OutliningMetadataCollector collector(IGF);
|
|
if (T.hasArchetype()) {
|
|
collectMetadataForOutlining(collector, T);
|
|
}
|
|
collector.emitCallToOutlinedCopy(dest, src, T, *this, isInit, isTake);
|
|
return;
|
|
}
|
|
|
|
if (!T.hasArchetype()) {
|
|
// Call the outlined copy function (the implementation will call vwt in this
|
|
// case).
|
|
OutliningMetadataCollector collector(IGF);
|
|
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 {
|
|
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());
|
|
addMetadataArguments(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(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;
|
|
}
|
|
|
|
bool isTypeMetadataForLayoutAccessible(SILModule &M, SILType type);
|
|
|
|
static bool canUseValueWitnessForValueOp(IRGenModule &IGM, SILType T) {
|
|
if (!IGM.getSILModule().isTypeMetadataForLayoutAccessible(T))
|
|
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().mangleOutlinedInitializeWithTakeFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.initializeWithTake(IGF, dest, src, T, 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().mangleOutlinedInitializeWithCopyFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling ||
|
|
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().mangleOutlinedAssignWithTakeFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling ||
|
|
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().mangleOutlinedAssignWithCopyFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
|
|
return getOrCreateOutlinedCopyAddrHelperFunction(
|
|
T, ti, collector, funcName,
|
|
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
|
|
const TypeInfo &ti) {
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling ||
|
|
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) {
|
|
auto ptrTy = ti.getStorageType()->getPointerTo();
|
|
|
|
llvm::SmallVector<llvm::Type *, 4> paramTys;
|
|
paramTys.push_back(ptrTy);
|
|
paramTys.push_back(ptrTy);
|
|
collector.addMetadataParameterTypes(paramTys);
|
|
|
|
return getOrCreateHelperFunction(funcName, ptrTy, paramTys,
|
|
[&](IRGenFunction &IGF) {
|
|
auto params = IGF.collectParameters();
|
|
Address src = ti.getAddressForPointer(params.claimNext());
|
|
Address dest = ti.getAddressForPointer(params.claimNext());
|
|
collector.bindMetadataParameters(IGF, params);
|
|
generator(IGF, dest, src, T, ti);
|
|
IGF.Builder.CreateRet(dest.getAddress());
|
|
},
|
|
true /*setIsNoInline*/);
|
|
}
|
|
|
|
void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
|
|
Address addr, SILType T) const {
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling) {
|
|
OutliningMetadataCollector collector(IGF);
|
|
if (T.hasArchetype()) {
|
|
collectMetadataForOutlining(collector, T);
|
|
}
|
|
collector.emitCallToOutlinedDestroy(addr, T, *this);
|
|
return;
|
|
}
|
|
|
|
if (!T.hasArchetype()) {
|
|
// Call the outlined copy function (the implementation will call vwt in this
|
|
// case).
|
|
OutliningMetadataCollector collector(IGF);
|
|
collector.emitCallToOutlinedDestroy(addr, T, *this);
|
|
return;
|
|
}
|
|
|
|
return emitDestroyCall(IGF, T, addr);
|
|
}
|
|
|
|
void OutliningMetadataCollector::emitCallToOutlinedDestroy(
|
|
Address addr, SILType T, const TypeInfo &ti) const {
|
|
llvm::SmallVector<llvm::Value *, 4> args;
|
|
args.push_back(IGF.Builder.CreateElementBitCast(addr, ti.getStorageType())
|
|
.getAddress());
|
|
addMetadataArguments(args);
|
|
|
|
auto outlinedFn =
|
|
IGF.IGM.getOrCreateOutlinedDestroyFunction(T, ti, *this);
|
|
|
|
llvm::CallInst *call = IGF.Builder.CreateCall(outlinedFn, args);
|
|
call->setCallingConv(IGF.IGM.DefaultCC);
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction(
|
|
SILType T, const TypeInfo &ti,
|
|
const OutliningMetadataCollector &collector) {
|
|
IRGenMangler mangler;
|
|
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
|
|
auto funcName = mangler.mangleOutlinedDestroyFunction(manglingBits.first,
|
|
manglingBits.second);
|
|
|
|
auto ptrTy = ti.getStorageType()->getPointerTo();
|
|
llvm::SmallVector<llvm::Type *, 4> paramTys;
|
|
paramTys.push_back(ptrTy);
|
|
collector.addMetadataParameterTypes(paramTys);
|
|
|
|
return getOrCreateHelperFunction(funcName, ptrTy, paramTys,
|
|
[&](IRGenFunction &IGF) {
|
|
Explosion params = IGF.collectParameters();
|
|
Address addr = ti.getAddressForPointer(params.claimNext());
|
|
collector.bindMetadataParameters(IGF, params);
|
|
if (!IGF.IGM.getOptions().UseTypeLayoutValueHandling ||
|
|
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
|
|
ti.destroy(IGF, addr, T, true);
|
|
} else {
|
|
emitDestroyCall(IGF, T, addr);
|
|
}
|
|
|
|
IGF.Builder.CreateRet(addr.getAddress());
|
|
},
|
|
true /*setIsNoInline*/);
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti,
|
|
SILType t,
|
|
llvm::Type *llvmType) {
|
|
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
|
|
IRGenMangler mangler;
|
|
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->getFixedAlignment());
|
|
Explosion loaded;
|
|
loadableTI->loadAsTake(IGF, addr, loaded);
|
|
Explosion out;
|
|
loadableTI->copy(IGF, loaded, out, irgen::Atomicity::Atomic);
|
|
(void)out.claimAll();
|
|
IGF.Builder.CreateRet(addr.getAddress());
|
|
},
|
|
true /*setIsNoInline*/);
|
|
}
|
|
|
|
llvm::Constant *
|
|
IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti,
|
|
SILType t,
|
|
llvm::Type *llvmType) {
|
|
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
|
|
IRGenMangler mangler;
|
|
auto manglingBits =
|
|
getTypeAndGenericSignatureForManglingOutlineFunction(t);
|
|
auto funcName = mangler.mangleOutlinedReleaseFunction(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->getFixedAlignment());
|
|
Explosion loaded;
|
|
loadableTI->loadAsTake(IGF, addr, loaded);
|
|
loadableTI->consume(IGF, loaded, irgen::Atomicity::Atomic);
|
|
IGF.Builder.CreateRet(addr.getAddress());
|
|
},
|
|
true /*setIsNoInline*/);
|
|
}
|