Skip to content
Open
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
13 changes: 12 additions & 1 deletion lib/IRGen/GenEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,11 @@ class EnumImplStrategy {
virtual void getSchema(ExplosionSchema &schema) const = 0;
virtual void destroy(IRGenFunction &IGF, Address addr, SILType T,
bool isOutlined) const = 0;

virtual std::string encodeDestroy(IRGenModule &IGM, Alignment alignment,
Size &offset, bool &outIsSupported) const {
outIsSupported = false;
return "";
}
virtual void initializeFromParams(IRGenFunction &IGF, Explosion &params,
Address dest, SILType T,
bool isOutlined) const;
Expand All @@ -375,6 +379,13 @@ class EnumImplStrategy {
SILType T, bool isOutlined) const = 0;
virtual void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const = 0;
virtual std::string encodeInitializeWithCopy(IRGenModule &IGM,
Alignment alignment,
Size &offset,
bool &outIsSupported) const {
outIsSupported = false;
return "";
}
virtual void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const = 0;

Expand Down
210 changes: 158 additions & 52 deletions lib/IRGen/GenFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#include "swift/AST/Module.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ReferenceCounting.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Types.h"
#include "swift/IRGen/Linking.h"
Expand All @@ -88,6 +89,8 @@
#include "llvm/IR/Module.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ScopedPrinter.h"

#include "BitPatternBuilder.h"
#include "Callee.h"
Expand Down Expand Up @@ -307,6 +310,10 @@ namespace {
}
}

bool supportsEncodingInitializeWithCopyAndDestroy() const override {
return true;
}

static Size getFirstElementSize(IRGenModule &IGM) {
return IGM.getPointerSize();
}
Expand Down Expand Up @@ -362,6 +369,15 @@ namespace {
else
IGF.emitNativeStrongAssign(context, dataAddr);
}
std::string encodeRetainSecondElement() const override {
if (isTriviallyDestroyable(ResilienceExpansion::Maximal)) {
return "";
}
return refcountingToString(ReferenceCounting::Native);
}
std::string encodeReleaseSecondElement() const override {
return encodeRetainSecondElement();
}

Address projectFunction(IRGenFunction &IGF, Address address) const {
return projectFirstElement(IGF, address);
Expand Down Expand Up @@ -2257,23 +2273,50 @@ llvm::Optional<StackAddress> irgen::emitFunctionPartialApplication(
return stackAddr;
}

std::string
irgen::getBlockCaptureInitializeKindEncoding(BlockCaptureInitializeKind kind) {
switch (kind) {
case BlockCaptureInitializeKind::Store:
return "S";
}
llvm_unreachable("unhandled BlockCaptureInitializeKind");
}

/// Emit the block copy helper for a block.
static llvm::Function *emitBlockCopyHelper(IRGenModule &IGM,
CanSILBlockStorageType blockTy,
const BlockStorageTypeInfo &blockTL){
// See if we've produced a block copy helper for this type before.
// TODO

auto &captureTL = IGM.getTypeInfoForLowered(blockTy->getCaptureType());
std::string funcName = "block_copy_helper";
bool helperCanBeReused = false;
const auto helperEncoding = captureTL.encodeInitializeWithCopy(
IGM, blockTL.getFixedAlignment(), helperCanBeReused);
if (helperCanBeReused) {
funcName = funcName + "_" +
llvm::to_string(blockTL.getFixedAlignment().getValue()) + "_" +
helperEncoding;
if (auto f = IGM.getModule()->getFunction(funcName))
return f;
}

// Create the helper.
llvm::Type *args[] = {
blockTL.getStorageType()->getPointerTo(),
blockTL.getStorageType()->getPointerTo(),
};
auto copyTy = llvm::FunctionType::get(IGM.VoidTy, args, /*vararg*/ false);
// TODO: Give these predictable mangled names and shared linkage.
auto func = llvm::Function::Create(copyTy, llvm::GlobalValue::InternalLinkage,
"block_copy_helper",
IGM.getModule());
auto func = llvm::Function::Create(copyTy,
helperCanBeReused
? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage,
funcName, IGM.getModule());
if (helperCanBeReused) {
if (IGM.Triple.supportsCOMDAT())
func->setComdat(IGM.Module.getOrInsertComdat(funcName));
func->setVisibility(llvm::GlobalValue::HiddenVisibility);
func->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
}
func->setAttributes(IGM.constructInitialAttributes());
IRGenFunction IGF(IGM, func);
if (IGM.DebugInfo)
Expand All @@ -2288,7 +2331,6 @@ static llvm::Function *emitBlockCopyHelper(IRGenModule &IGM,

auto destCapture = blockTL.projectCapture(IGF, dest);
auto srcCapture = blockTL.projectCapture(IGF, src);
auto &captureTL = IGM.getTypeInfoForLowered(blockTy->getCaptureType());
captureTL.initializeWithCopy(IGF, destCapture, srcCapture,
blockTy->getCaptureAddressType(), false);

Expand All @@ -2302,17 +2344,34 @@ static llvm::Function *emitBlockDisposeHelper(IRGenModule &IGM,
CanSILBlockStorageType blockTy,
const BlockStorageTypeInfo &blockTL){
// See if we've produced a block destroy helper for this type before.
// TODO

auto &captureTL = IGM.getTypeInfoForLowered(blockTy->getCaptureType());
std::string funcName = "block_destroy_helper";
bool helperCanBeReused = false;
const auto helperEncoding = captureTL.encodeDestroy(
IGM, blockTL.getFixedAlignment(), helperCanBeReused);
if (helperCanBeReused) {
funcName = funcName + "_" +
llvm::to_string(blockTL.getFixedAlignment().getValue()) + "_" +
helperEncoding;
if (auto f = IGM.getModule()->getFunction(funcName))
return f;
}

// Create the helper.
auto destroyTy = llvm::FunctionType::get(IGM.VoidTy,
blockTL.getStorageType()->getPointerTo(),
/*vararg*/ false);
// TODO: Give these predictable mangled names and shared linkage.
auto destroyTy = llvm::FunctionType::get(
IGM.VoidTy, blockTL.getStorageType()->getPointerTo(),
/*vararg*/ false);
auto func = llvm::Function::Create(destroyTy,
llvm::GlobalValue::InternalLinkage,
"block_destroy_helper",
IGM.getModule());
helperCanBeReused
? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage,
funcName, IGM.getModule());
if (helperCanBeReused) {
if (IGM.Triple.supportsCOMDAT())
func->setComdat(IGM.Module.getOrInsertComdat(funcName));
func->setVisibility(llvm::GlobalValue::HiddenVisibility);
func->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
}
func->setAttributes(IGM.constructInitialAttributes());
IRGenFunction IGF(IGM, func);
assert(!func->hasFnAttribute(llvm::Attribute::SanitizeThread));
Expand All @@ -2324,14 +2383,92 @@ static llvm::Function *emitBlockDisposeHelper(IRGenModule &IGM,
auto storage = Address(params.claimNext(), blockTL.getStorageType(),
blockTL.getFixedAlignment());
auto capture = blockTL.projectCapture(IGF, storage);
auto &captureTL = IGM.getTypeInfoForLowered(blockTy->getCaptureType());
captureTL.destroy(IGF, capture, blockTy->getCaptureAddressType(),
false /*block storage code path: never outlined*/);
IGF.Builder.CreateRetVoid();

return func;
}

static llvm::Constant *
buildBlockDescriptor(IRGenFunction &IGF, const BlockStorageTypeInfo &storageTL,
bool isTriviallyDestroyable, CanSILFunctionType invokeTy,
CanSILBlockStorageType blockTy) {
// Lookup identical descriptor created before if capture type allows us to
// reuse.
auto &captureTL = IGF.IGM.getTypeInfoForLowered(blockTy->getCaptureType());
auto blockStorageSize = storageTL.getFixedSize().getValue();
std::string descriptorName = "block_descriptor";
bool initializeWithCopyCanReuse = false;
bool destroyCanReuse = false;
const auto initializeWithCopyEncoding = captureTL.encodeInitializeWithCopy(
IGF.IGM, storageTL.getFixedAlignment(), initializeWithCopyCanReuse);
const auto destroyEncoding =
initializeWithCopyCanReuse
? captureTL.encodeDestroy(IGF.IGM, storageTL.getFixedAlignment(),
destroyCanReuse)
: "";
const bool descriptorCanReuse =
isTriviallyDestroyable || (initializeWithCopyCanReuse && destroyCanReuse);
if (descriptorCanReuse) {
descriptorName += "_" + llvm::to_string(blockStorageSize) + "_";
if (!isTriviallyDestroyable) {
descriptorName +=
llvm::to_string(storageTL.getFixedAlignment().getValue()) + "_";
descriptorName += initializeWithCopyEncoding + "_" + destroyEncoding;
}
auto typeEncoding = getBlockTypeExtendedEncodingString(IGF.IGM, invokeTy);
// Replace occurrences of '@' with '\1'. '@' is reserved on ELF platforms as
// a separator between symbol name and symbol version.
std::replace(typeEncoding.begin(), typeEncoding.end(), '@', '\1');
descriptorName += typeEncoding;
if (auto descriptor = IGF.IGM.getModule()->getNamedValue(descriptorName)) {
return descriptor;
}
}

// Build the block descriptor.
ConstantInitBuilder builder(IGF.IGM);
auto descriptorFields = builder.beginStruct();

const clang::ASTContext &ASTContext = IGF.IGM.getClangASTContext();
llvm::IntegerType *UnsignedLongTy =
llvm::IntegerType::get(IGF.IGM.getLLVMContext(),
ASTContext.getTypeSize(ASTContext.UnsignedLongTy));
descriptorFields.addInt(UnsignedLongTy, 0);
descriptorFields.addInt(UnsignedLongTy, blockStorageSize);

if (!isTriviallyDestroyable) {
// Define the copy and dispose helpers.
descriptorFields.addSignedPointer(
emitBlockCopyHelper(IGF.IGM, blockTy, storageTL),
IGF.getOptions().PointerAuth.BlockHelperFunctionPointers,
PointerAuthEntity::Special::BlockCopyHelper);
descriptorFields.addSignedPointer(
emitBlockDisposeHelper(IGF.IGM, blockTy, storageTL),
IGF.getOptions().PointerAuth.BlockHelperFunctionPointers,
PointerAuthEntity::Special::BlockDisposeHelper);
}

// Build the descriptor signature.
descriptorFields.add(getBlockTypeExtendedEncoding(IGF.IGM, invokeTy));

// Create the descriptor.
auto descriptor = descriptorFields.finishAndCreateGlobal(
descriptorName, IGF.IGM.getPointerAlignment(),
/*constant*/ true,
descriptorCanReuse ? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage);
if (descriptorCanReuse) {
if (IGF.IGM.Triple.supportsCOMDAT())
descriptor->setComdat(IGF.IGM.Module.getOrInsertComdat(descriptorName));
descriptor->setVisibility(llvm::GlobalValue::HiddenVisibility);
descriptor->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
}

return descriptor;
}

/// Emit the block header into a block storage slot.
void irgen::emitBlockHeader(IRGenFunction &IGF,
Address storage,
Expand Down Expand Up @@ -2374,42 +2511,11 @@ void irgen::emitBlockHeader(IRGenFunction &IGF,

// Collect the reserved and invoke pointer fields.
auto reserved = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0);
llvm::Value *invokeVal = llvm::ConstantExpr::getBitCast(invokeFunction,
IGF.IGM.FunctionPtrTy);

// Build the block descriptor.
ConstantInitBuilder builder(IGF.IGM);
auto descriptorFields = builder.beginStruct();

const clang::ASTContext &ASTContext = IGF.IGM.getClangASTContext();
llvm::IntegerType *UnsignedLongTy =
llvm::IntegerType::get(IGF.IGM.getLLVMContext(),
ASTContext.getTypeSize(ASTContext.UnsignedLongTy));
descriptorFields.addInt(UnsignedLongTy, 0);
descriptorFields.addInt(UnsignedLongTy,
storageTL.getFixedSize().getValue());

if (!isTriviallyDestroyable) {
// Define the copy and dispose helpers.
descriptorFields.addSignedPointer(
emitBlockCopyHelper(IGF.IGM, blockTy, storageTL),
IGF.getOptions().PointerAuth.BlockHelperFunctionPointers,
PointerAuthEntity::Special::BlockCopyHelper);
descriptorFields.addSignedPointer(
emitBlockDisposeHelper(IGF.IGM, blockTy, storageTL),
IGF.getOptions().PointerAuth.BlockHelperFunctionPointers,
PointerAuthEntity::Special::BlockDisposeHelper);
}

// Build the descriptor signature.
descriptorFields.add(getBlockTypeExtendedEncoding(IGF.IGM, invokeTy));

// Create the descriptor.
auto descriptor =
descriptorFields.finishAndCreateGlobal("block_descriptor",
IGF.IGM.getPointerAlignment(),
/*constant*/ true);
llvm::Value *invokeVal =
llvm::ConstantExpr::getBitCast(invokeFunction, IGF.IGM.FunctionPtrTy);

auto descriptor = buildBlockDescriptor(IGF, storageTL, isTriviallyDestroyable,
invokeTy, blockTy);
auto descriptorVal = llvm::ConstantExpr::getBitCast(descriptor,
IGF.IGM.Int8PtrTy);

Expand Down
7 changes: 7 additions & 0 deletions lib/IRGen/GenFunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ namespace irgen {
class ForeignFunctionInfo;
class IRGenFunction;

enum class BlockCaptureInitializeKind {
Store,
};

std::string
getBlockCaptureInitializeKindEncoding(BlockCaptureInitializeKind kind);

/// Project the capture address from on-stack block storage.
Address projectBlockStorageCapture(IRGenFunction &IGF,
Address storageAddr,
Expand Down
Loading