diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h index 53f35c47c4311..ae0222074df00 100644 --- a/lib/IRGen/GenEnum.h +++ b/lib/IRGen/GenEnum.h @@ -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 ¶ms, Address dest, SILType T, bool isOutlined) const; @@ -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; diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index 0d2cd436ca16d..7905f74587ebe 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -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" @@ -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" @@ -307,6 +310,10 @@ namespace { } } + bool supportsEncodingInitializeWithCopyAndDestroy() const override { + return true; + } + static Size getFirstElementSize(IRGenModule &IGM) { return IGM.getPointerSize(); } @@ -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); @@ -2257,23 +2273,50 @@ llvm::Optional 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) @@ -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); @@ -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)); @@ -2324,7 +2383,6 @@ 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(); @@ -2332,6 +2390,85 @@ static llvm::Function *emitBlockDisposeHelper(IRGenModule &IGM, 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, @@ -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); diff --git a/lib/IRGen/GenFunc.h b/lib/IRGen/GenFunc.h index 0b96c17e04a30..e906ba34e833f 100644 --- a/lib/IRGen/GenFunc.h +++ b/lib/IRGen/GenFunc.h @@ -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, diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index a908c6c723759..f749ab6086172 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -1244,12 +1244,10 @@ HelperGetObjCEncodingForType(const clang::ASTContext &Context, T, S, Extended); } -static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, - CanSILFunctionType fnType, - ArrayRef params, - StringRef fixedParamsString, - Size::int_type parmOffset, - bool useExtendedEncoding) { +static std::string getObjCEncodingStringForTypes( + IRGenModule &IGM, CanSILFunctionType fnType, + ArrayRef params, StringRef fixedParamsString, + Size::int_type parmOffset, bool useExtendedEncoding) { auto resultType = fnType->getFormalCSemanticResult(IGM.getSILModule()); auto &clangASTContext = IGM.getClangASTContext(); @@ -1259,7 +1257,7 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, { auto clangType = IGM.getClangType(resultType.getASTType()); if (clangType.isNull()) - return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); + return ""; HelperGetObjCEncodingForType(clangASTContext, clangType, encodingString, useExtendedEncoding); } @@ -1271,8 +1269,8 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, auto clangType = IGM.getClangType(param.getArgumentType( IGM.getSILModule(), fnType, IGM.getMaximalTypeExpansionContext())); if (clangType.isNull()) - return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); - + return ""; + // TODO. Some stuff related to Array and Function type is missing. // TODO. Encode type qualifier, 'in', 'inout', etc. for the parameter. HelperGetObjCEncodingForType(clangASTContext, clangType, paramsString, @@ -1285,6 +1283,19 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, encodingString += llvm::itostr(parmOffset); encodingString += fixedParamsString; encodingString += paramsString; + return encodingString; +} + +static llvm::Constant * +getObjCEncodingForTypes(IRGenModule &IGM, CanSILFunctionType fnType, + ArrayRef params, + StringRef fixedParamsString, Size::int_type parmOffset, + bool useExtendedEncoding) { + auto encodingString = getObjCEncodingStringForTypes( + IGM, fnType, params, fixedParamsString, parmOffset, useExtendedEncoding); + if (encodingString.empty()) { + return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); + } return IGM.getAddrOfGlobalString(encodingString); } @@ -1607,12 +1618,24 @@ irgen::getBlockTypeExtendedEncoding(IRGenModule &IGM, // Skip the storage pointer, which is encoded as '@?' to avoid the infinite // recursion of the usual '@?<...>' rule for blocks. auto paramTypes = invokeTy->getParameters().slice(1); - - return getObjCEncodingForTypes(IGM, invokeTy, paramTypes, - "@?0", IGM.getPointerSize().getValue(), + + return getObjCEncodingForTypes(IGM, invokeTy, paramTypes, "@?0", + IGM.getPointerSize().getValue(), /*extended*/ true); } +std::string +irgen::getBlockTypeExtendedEncodingString(IRGenModule &IGM, + CanSILFunctionType invokeTy) { + // Skip the storage pointer, which is encoded as '@?' to avoid the infinite + // recursion of the usual '@?<...>' rule for blocks. + auto paramTypes = invokeTy->getParameters().slice(1); + + return getObjCEncodingStringForTypes(IGM, invokeTy, paramTypes, "@?0", + IGM.getPointerSize().getValue(), + /*extended*/ true); +} + void irgen::emitObjCGetterDescriptor(IRGenModule &IGM, ConstantArrayBuilder &descriptors, AbstractStorageDecl *storage) { diff --git a/lib/IRGen/GenObjC.h b/lib/IRGen/GenObjC.h index 386b2e7aa8b43..e7d512632ed98 100644 --- a/lib/IRGen/GenObjC.h +++ b/lib/IRGen/GenObjC.h @@ -178,7 +178,10 @@ namespace irgen { /// \returns the encoded type. llvm::Constant *getBlockTypeExtendedEncoding(IRGenModule &IGM, CanSILFunctionType invokeTy); - + + std::string getBlockTypeExtendedEncodingString(IRGenModule &IGM, + CanSILFunctionType invokeTy); + /// Produces extended encoding of method type. /// \returns the encoded type. llvm::Constant *getMethodTypeExtendedEncoding(IRGenModule &IGM, diff --git a/lib/IRGen/HeapTypeInfo.h b/lib/IRGen/HeapTypeInfo.h index a9db4e0b5722c..d9c1aa2c65861 100644 --- a/lib/IRGen/HeapTypeInfo.h +++ b/lib/IRGen/HeapTypeInfo.h @@ -122,6 +122,16 @@ class HeapTypeInfo IGF.emitStrongRetain(value, asDerived().getReferenceCounting(), atomicity); } + bool supportsEncodingScalarRetain() const override { return true; } + std::string encodeScalarRetain(IRGenModule &IGM) const override { + return refcountingToString(asDerived().getReferenceCounting()); + } + bool supportsEncodingScalarRelease() const override { return true; } + std::string encodeScalarRelease(IRGenModule &IGM) const override { + return refcountingToString(asDerived().getReferenceCounting()); + } + Size getSizeForEncoding() const override { return super::getFixedSize(); } + // Implement the primary retain/release operations of ReferenceTypeInfo // using basic reference counting. void strongRetain(IRGenFunction &IGF, Explosion &e, diff --git a/lib/IRGen/ScalarPairTypeInfo.h b/lib/IRGen/ScalarPairTypeInfo.h index e065665abc0bd..e06f392ebe7da 100644 --- a/lib/IRGen/ScalarPairTypeInfo.h +++ b/lib/IRGen/ScalarPairTypeInfo.h @@ -19,8 +19,10 @@ #ifndef SWIFT_IRGEN_SCALARPAIRTYPEINFO_H #define SWIFT_IRGEN_SCALARPAIRTYPEINFO_H +#include "GenFunc.h" #include "NativeConventionSchema.h" #include "ScalarTypeInfo.h" +#include "llvm/Support/ScopedPrinter.h" namespace swift { namespace irgen { @@ -87,6 +89,50 @@ class ScalarPairTypeInfo : public ScalarTypeInfo { e.add(second); } + /// Subclasses that supports encoding initializeWithCopy and destroy + /// must implements encodeRetainFirstElement, encodeRetainSecondElement, + /// emitReleaseFirstElement and encodeReleaseSecondElement. + virtual bool supportsEncodingInitializeWithCopyAndDestroy() const { + return false; + } + virtual std::string encodeRetainFirstElement() const { return ""; } + virtual std::string encodeReleaseFirstElement() const { return ""; } + virtual std::string encodeRetainSecondElement() const { return ""; } + virtual std::string encodeReleaseSecondElement() const { return ""; } + + std::string encodeInitializeWithCopy(IRGenModule &IGM, Alignment alignment, + Size &offset, + bool &outIsSupported) const override { + if (!supportsEncodingInitializeWithCopyAndDestroy()) { + outIsSupported = false; + return ""; + } + outIsSupported = true; + + // Encode `loadAsCopy` behavior, followed by `initialize`. + std::string encoding; + if (!asDerived().isFirstElementTrivial()) { + encoding += llvm::to_string(offset.getValue()); + auto first = encodeRetainFirstElement(); + encoding += first; + encoding += getBlockCaptureInitializeKindEncoding( + BlockCaptureInitializeKind::Store); + } + + offset += + asDerived().getSecondElementOffset(IGM).roundUpToAlignment(alignment); + if (!asDerived().isSecondElementTrivial()) { + encoding += llvm::to_string(offset.getValue()); + auto second = encodeRetainSecondElement(); + encoding += second; + encoding += getBlockCaptureInitializeKindEncoding( + BlockCaptureInitializeKind::Store); + } + offset += + asDerived().getSecondElementSize(IGM).roundUpToAlignment(alignment); + return encoding; + } + void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const override { // Load the function. @@ -159,6 +205,33 @@ class ScalarPairTypeInfo : public ScalarTypeInfo { } } + std::string encodeDestroy(IRGenModule &IGM, Alignment alignment, Size &offset, + bool &outIsSupported) const override { + if (!supportsEncodingInitializeWithCopyAndDestroy()) { + outIsSupported = false; + return ""; + } + outIsSupported = true; + + std::string encoding; + if (!asDerived().isFirstElementTrivial()) { + encoding += llvm::to_string(offset.getValue()); + auto first = encodeReleaseFirstElement(); + encoding += first; + } + + offset += + asDerived().getSecondElementOffset(IGM).roundUpToAlignment(alignment); + if (!asDerived().isSecondElementTrivial()) { + encoding += llvm::to_string(offset.getValue()); + auto second = encodeReleaseSecondElement(); + encoding += second; + } + offset += + asDerived().getSecondElementSize(IGM).roundUpToAlignment(alignment); + return encoding; + } + void packIntoEnumPayload(IRGenModule &IGM, IRBuilder &builder, EnumPayload &payload, diff --git a/lib/IRGen/ScalarTypeInfo.h b/lib/IRGen/ScalarTypeInfo.h index 001bd85920a9c..c14cb03b0138f 100644 --- a/lib/IRGen/ScalarTypeInfo.h +++ b/lib/IRGen/ScalarTypeInfo.h @@ -21,9 +21,12 @@ #include "EnumPayload.h" #include "Explosion.h" -#include "TypeInfo.h" -#include "IRGenFunction.h" #include "GenEnum.h" +#include "GenFunc.h" +#include "IRGenFunction.h" +#include "TypeInfo.h" +#include "llvm/Support/ScopedPrinter.h" +#include namespace swift { namespace irgen { @@ -54,6 +57,29 @@ class ScalarTypeInfo : public Base { asDerived().Derived::initialize(IGF, temp, dest, isOutlined); } + /// Subclasses that supports encoding initializeWithCopy must implements + /// encodeLoadAsCopy, encodeInitialize and getSizeForEncoding. + virtual bool supportsEncodingInitializeWithCopy() const { return false; } + virtual std::string encodeLoadAsCopy(IRGenModule &IGM) const { return ""; } + virtual std::string encodeInitialize() const { return ""; } + virtual Size getSizeForEncoding() const { return Size(); } + + std::string encodeInitializeWithCopy(IRGenModule &IGM, Alignment alignment, + Size &offset, + bool &outIsSupported) const override { + if (!supportsEncodingInitializeWithCopy()) { + outIsSupported = false; + return ""; + } + outIsSupported = true; + std::string encoding; + encoding += llvm::to_string(offset.getValue()); + encoding += encodeLoadAsCopy(IGM); + encoding += encodeInitialize(); + offset += getSizeForEncoding().roundUpToAlignment(alignment); + return encoding; + } + void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T, bool isOutlined) const override { Explosion temp; @@ -146,6 +172,11 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { storeAsBytes(IGF, src, addr); } + std::string encodeInitialize() const override { + return getBlockCaptureInitializeKindEncoding( + BlockCaptureInitializeKind::Store); + } + void loadAsCopy(IRGenFunction &IGF, Address addr, Explosion &out) const override { addr = asDerived().projectScalar(IGF, addr); @@ -154,6 +185,17 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { out.add(value); } + /// Subclasses that supports encoding initializeWithCopy must implements + /// encodeScalarRetain. + virtual bool supportsEncodingScalarRetain() const { return false; } + bool supportsEncodingInitializeWithCopy() const override { + return supportsEncodingScalarRetain(); + } + virtual std::string encodeScalarRetain(IRGenModule &IGM) const { return ""; } + std::string encodeLoadAsCopy(IRGenModule &IGM) const override { + return encodeScalarRetain(IGM); + } + void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &out) const override { addr = asDerived().projectScalar(IGF, addr); @@ -206,7 +248,28 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { asDerived().emitScalarRelease(IGF, value, IGF.getDefaultAtomicity()); } } - + + /// Subclasses that supports encoding destroy must implements + /// encodeScalarRelease and getSizeForEncoding. + virtual bool supportsEncodingScalarRelease() const { return false; } + virtual std::string encodeScalarRelease(IRGenModule &IGM) const { return ""; } + + std::string encodeDestroy(IRGenModule &IGM, Alignment alignment, Size &offset, + bool &outIsSupported) const override { + if (!supportsEncodingScalarRelease()) { + outIsSupported = false; + return ""; + } + outIsSupported = true; + std::string encoding; + if (!Derived::IsScalarTriviallyDestroyable) { + encoding += llvm::to_string(offset.getValue()); + encoding += asDerived().encodeScalarRelease(IGM); + } + offset += asDerived().getSizeForEncoding().roundUpToAlignment(alignment); + return encoding; + } + void packIntoEnumPayload(IRGenModule &IGM, IRBuilder &builder, EnumPayload &payload, diff --git a/lib/IRGen/TypeInfo.h b/lib/IRGen/TypeInfo.h index 0ac8933a4be30..718979207c9ca 100644 --- a/lib/IRGen/TypeInfo.h +++ b/lib/IRGen/TypeInfo.h @@ -29,6 +29,8 @@ #include "swift/AST/ReferenceCounting.h" #include "llvm/ADT/MapVector.h" +#include + namespace llvm { class Constant; class Twine; @@ -378,6 +380,22 @@ class TypeInfo { Address srcAddr, SILType T, bool isOutlined) const = 0; + /// Encode the behavior of initializeWithCopy into a string. + /// Subclasses that supports the encoding should set the out parameter + /// outIsSupported to true. + virtual std::string encodeInitializeWithCopy(IRGenModule &IGM, + Alignment alignment, + Size &offset, + bool &outIsSupported) const { + outIsSupported = false; + return ""; + } + std::string encodeInitializeWithCopy(IRGenModule &IGM, Alignment alignment, + bool &outIsSupported) const { + Size offset; + return encodeInitializeWithCopy(IGM, alignment, offset, outIsSupported); + } + /// Perform a copy-initialization from the given fixed-size buffer /// into an uninitialized fixed-size buffer, allocating the buffer if /// necessary. Returns the address of the value inside the buffer. @@ -401,6 +419,20 @@ class TypeInfo { virtual void destroy(IRGenFunction &IGF, Address address, SILType T, bool isOutlined) const = 0; + /// Encode the behavior of destroy into a string. + /// Subclasses that supports the encoding should set the out parameter + /// outIsSupported to true. + virtual std::string encodeDestroy(IRGenModule &IGM, Alignment alignment, + Size &offset, bool &outIsSupported) const { + outIsSupported = false; + return ""; + } + std::string encodeDestroy(IRGenModule &IGM, Alignment alignment, + bool &outIsSupported) const { + Size offset; + return encodeDestroy(IGM, alignment, offset, outIsSupported); + } + /// Should optimizations be enabled which rely on the representation /// for this type being a single object pointer? /// diff --git a/lib/IRGen/TypeLayout.cpp b/lib/IRGen/TypeLayout.cpp index 107b7395d0fa8..34bd80d10b4c8 100644 --- a/lib/IRGen/TypeLayout.cpp +++ b/lib/IRGen/TypeLayout.cpp @@ -13,16 +13,17 @@ #include "ConstantBuilder.h" #include "EnumPayload.h" #include "FixedTypeInfo.h" -#include "GenOpaque.h" -#include "IRGen.h" #include "GenEnum.h" #include "GenExistential.h" +#include "GenOpaque.h" #include "GenericArguments.h" +#include "IRGen.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "SwitchBuilder.h" #include "swift/ABI/MetadataValues.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/ReferenceCounting.h" #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/None.h" #include "llvm/IR/DerivedTypes.h" @@ -464,6 +465,10 @@ static std::string scalarToString(ScalarKind kind) { } } +std::string swift::irgen::refcountingToString(ReferenceCounting refCounting) { + return scalarToString(refcountingToScalarKind(refCounting)); +} + llvm::Function *createMetatypeAccessorFunction(IRGenModule &IGM, SILType ty, GenericSignature genericSig) { CanType fieldType = ty.getASTType(); diff --git a/lib/IRGen/TypeLayout.h b/lib/IRGen/TypeLayout.h index 7831846adeb29..e2dd95e80c1c9 100644 --- a/lib/IRGen/TypeLayout.h +++ b/lib/IRGen/TypeLayout.h @@ -15,6 +15,7 @@ #include "FixedTypeInfo.h" #include "TypeInfo.h" +#include "swift/AST/ReferenceCounting.h" #include "swift/SIL/SILType.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Debug.h" @@ -57,6 +58,8 @@ enum class ScalarKind : uint8_t { /// Convert a ReferenceCounting into the appropriate Scalar reference ScalarKind refcountingToScalarKind(ReferenceCounting refCounting); +std::string refcountingToString(ReferenceCounting refCounting); + class TypeLayoutEntry { protected: /// Memoize the value of layoutString() diff --git a/test/IRGen/objc_block_storage.sil b/test/IRGen/objc_block_storage.sil index 5ecd6d590d1a5..5b9398defa187 100644 --- a/test/IRGen/objc_block_storage.sil +++ b/test/IRGen/objc_block_storage.sil @@ -13,18 +13,18 @@ import gizmo // CHECK: [[BLOCK_ISA:@_NSConcreteStackBlock]] = external global {{(dllimport )?}}%objc_class // CHECK: [[VOID_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"v8@?0\00" -// CHECK: [[TRIVIAL_BLOCK_DESCRIPTOR:@.*]] = internal constant { i64, i64, ptr } { +// CHECK: [[TRIVIAL_BLOCK_DESCRIPTOR:@"block_descriptor_40_v8\\01\?0"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr } { // CHECK-SAME: i64 0, // CHECK-SAME: i64 40, // CHECK-SAME: ptr [[VOID_BLOCK_SIGNATURE]] // CHECK-SAME: } // CHECK: [[BLOCK_PARAM_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"v16@?0@?8\00" -// CHECK: [[BLOCK_PARAM_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } { +// CHECK: [[BLOCK_PARAM_BLOCK_DESCRIPTOR:@"block_descriptor_40_v16\\01\?0\\01\?8"]] = linkonce_odr hidden unnamed_addr constant { {{.*}} } { // CHECK: i64 0, // CHECK: i64 40, // CHECK: ptr [[BLOCK_PARAM_BLOCK_SIGNATURE]] // CHECK: } -// CHECK: [[NONTRIVIAL_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } { +// CHECK: [[NONTRIVIAL_BLOCK_DESCRIPTOR:@"block_descriptor_40_8_0NativeStrongReferenceS_0NativeStrongReferencev8\\01\?0"]] = linkonce_odr hidden unnamed_addr constant { {{.*}} } { // CHECK: i64 0, // CHECK: i64 40, // CHECK: ptr [[NONTRIVIAL_BLOCK_COPY:@[A-Za-z0-9_]+]], @@ -32,7 +32,7 @@ import gizmo // CHECK: ptr [[VOID_BLOCK_SIGNATURE]] // CHECK: } // CHECK: [[NSRECT_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"{NSRect={NSPoint=dd}{NSSize=dd}}8@?0\00" -// CHECK: [[STRET_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } { +// CHECK: [[STRET_BLOCK_DESCRIPTOR:@"block_descriptor_40_{NSRect={NSPoint=dd}{NSSize=dd}}8\\01\?0"]] = linkonce_odr hidden unnamed_addr constant { {{.*}} } { // CHECK: i64 0, // CHECK: i64 40, // CHECK: ptr [[NSRECT_BLOCK_SIGNATURE]] @@ -129,7 +129,7 @@ entry(%0 : $*@block_storage Builtin.NativeObject): return %b : $@convention(block) () -> () } -// CHECK: define internal void [[NONTRIVIAL_BLOCK_COPY]] +// CHECK: define linkonce_odr hidden void [[NONTRIVIAL_BLOCK_COPY]] // CHECK-NEXT: entry: // CHECK-NEXT: %2 = getelementptr inbounds { %objc_block, ptr }, ptr %0, i32 0, i32 1 // CHECK-NEXT: %3 = getelementptr inbounds { %objc_block, ptr }, ptr %1, i32 0, i32 1 @@ -138,7 +138,7 @@ entry(%0 : $*@block_storage Builtin.NativeObject): // CHECK-NEXT: store ptr %4, ptr %2, align 8 // CHECK-NEXT: ret void -// CHECK: define internal void [[NONTRIVIAL_BLOCK_DISPOSE]] +// CHECK: define linkonce_odr hidden void [[NONTRIVIAL_BLOCK_DISPOSE]] // CHECK-NEXT: entry: // CHECK-NEXT: %1 = getelementptr inbounds { %objc_block, ptr }, ptr %0, i32 0, i32 1 // CHECK-NEXT: %toDestroy = load ptr, ptr %1, align 8