diff options
author | Akira Hatanaka <ahatanaka@apple.com> | 2018-08-17 15:46:07 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@apple.com> | 2018-08-17 15:46:07 +0000 |
commit | 2ec36f08a6cce7aa6f2e0ae5a1f62a475148baf5 (patch) | |
tree | 35fa22b9cfe8f3ad7588481632c68dd4e12f27e0 /clang/lib | |
parent | 6c9f15c533811937b51be1e1f8975fc54e18f40b (diff) | |
download | bcm5719-llvm-2ec36f08a6cce7aa6f2e0ae5a1f62a475148baf5.tar.gz bcm5719-llvm-2ec36f08a6cce7aa6f2e0ae5a1f62a475148baf5.zip |
[CodeGen] Merge identical block descriptor global variables.
Currently, clang generates a new block descriptor global variable for
each new block literal. This commit merges block descriptors that are
identical inside and across translation units using the same approach
taken in r339438.
To enable merging identical block descriptors, the size and signature of
the block and information about the captures are encoded into the name
of the block descriptor variable. Also, the block descriptor variable is
marked as linkonce_odr and unnamed_addr.
rdar://problem/42640703
Differential Revision: https://reviews.llvm.org/D50783
llvm-svn: 340041
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGBlocks.cpp | 403 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGBlocks.h | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjCMac.cpp | 59 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjCRuntime.h | 4 |
4 files changed, 337 insertions, 132 deletions
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index c5066f48296..8b8b6ca66f6 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -65,6 +65,107 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM, return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo); } +namespace { + +/// Represents a type of copy/destroy operation that should be performed for an +/// entity that's captured by a block. +enum class BlockCaptureEntityKind { + CXXRecord, // Copy or destroy + ARCWeak, + ARCStrong, + NonTrivialCStruct, + BlockObject, // Assign or release + None +}; + +/// Represents a captured entity that requires extra operations in order for +/// this entity to be copied or destroyed correctly. +struct BlockCaptureManagedEntity { + BlockCaptureEntityKind CopyKind, DisposeKind; + BlockFieldFlags CopyFlags, DisposeFlags; + const BlockDecl::Capture *CI; + const CGBlockInfo::Capture *Capture; + + BlockCaptureManagedEntity(BlockCaptureEntityKind CopyType, + BlockCaptureEntityKind DisposeType, + BlockFieldFlags CopyFlags, + BlockFieldFlags DisposeFlags, + const BlockDecl::Capture &CI, + const CGBlockInfo::Capture &Capture) + : CopyKind(CopyType), DisposeKind(DisposeType), CopyFlags(CopyFlags), + DisposeFlags(DisposeFlags), CI(&CI), Capture(&Capture) {} + + bool operator<(const BlockCaptureManagedEntity &Other) const { + return Capture->getOffset() < Other.Capture->getOffset(); + } +}; + +enum class CaptureStrKind { + // String for the copy helper. + CopyHelper, + // String for the dispose helper. + DisposeHelper, + // Merge the strings for the copy helper and dispose helper. + Merged +}; + +} // end anonymous namespace + +static void findBlockCapturedManagedEntities( + const CGBlockInfo &BlockInfo, const LangOptions &LangOpts, + SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures); + +static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, + CaptureStrKind StrKind, + CharUnits BlockAlignment, + CodeGenModule &CGM); + +static std::string getBlockDescriptorName(const CGBlockInfo &BlockInfo, + CodeGenModule &CGM) { + std::string Name = "__block_descriptor_"; + Name += llvm::to_string(BlockInfo.BlockSize.getQuantity()) + "_"; + + if (BlockInfo.needsCopyDisposeHelpers()) { + if (CGM.getLangOpts().Exceptions) + Name += "e"; + if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions) + Name += "a"; + Name += llvm::to_string(BlockInfo.BlockAlign.getQuantity()) + "_"; + + SmallVector<BlockCaptureManagedEntity, 4> ManagedCaptures; + findBlockCapturedManagedEntities(BlockInfo, CGM.getContext().getLangOpts(), + ManagedCaptures); + + for (const BlockCaptureManagedEntity &E : ManagedCaptures) { + Name += llvm::to_string(E.Capture->getOffset().getQuantity()); + + if (E.CopyKind == E.DisposeKind) { + // If CopyKind and DisposeKind are the same, merge the capture + // information. + assert(E.CopyKind != BlockCaptureEntityKind::None && + "shouldn't see BlockCaptureManagedEntity that is None"); + Name += getBlockCaptureStr(E, CaptureStrKind::Merged, + BlockInfo.BlockAlign, CGM); + } else { + // If CopyKind and DisposeKind are not the same, which can happen when + // either Kind is None or the captured object is a __strong block, + // concatenate the copy and dispose strings. + Name += getBlockCaptureStr(E, CaptureStrKind::CopyHelper, + BlockInfo.BlockAlign, CGM); + Name += getBlockCaptureStr(E, CaptureStrKind::DisposeHelper, + BlockInfo.BlockAlign, CGM); + } + } + Name += "_"; + } + + std::string TypeAtEncoding = + CGM.getContext().getObjCEncodingForBlock(BlockInfo.getBlockExpr()); + Name += "e" + llvm::to_string(TypeAtEncoding.size()) + "_" + TypeAtEncoding; + Name += "l" + CGM.getObjCRuntime().getRCBlockLayoutStr(CGM, BlockInfo); + return Name; +} + /// buildBlockDescriptor - Build the block descriptor meta-data for a block. /// buildBlockDescriptor is accessed from 5th field of the Block_literal /// meta-data and contains stationary information about the block literal. @@ -93,6 +194,19 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, else i8p = CGM.VoidPtrTy; + std::string descName; + + // If an equivalent block descriptor global variable exists, return it. + if (C.getLangOpts().ObjC1 && + CGM.getLangOpts().getGC() == LangOptions::NonGC) { + descName = getBlockDescriptorName(blockInfo, CGM); + if (llvm::GlobalValue *desc = CGM.getModule().getNamedValue(descName)) + return llvm::ConstantExpr::getBitCast(desc, + CGM.getBlockDescriptorType()); + } + + // If there isn't an equivalent block descriptor global variable, create a new + // one. ConstantInitBuilder builder(CGM); auto elements = builder.beginStruct(); @@ -106,12 +220,20 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, elements.addInt(ulong, blockInfo.BlockSize.getQuantity()); // Optional copy/dispose helpers. + bool hasInternalHelper = false; if (blockInfo.needsCopyDisposeHelpers()) { // copy_func_helper_decl - elements.add(buildCopyHelper(CGM, blockInfo)); + llvm::Constant *copyHelper = buildCopyHelper(CGM, blockInfo); + elements.add(copyHelper); // destroy_func_decl - elements.add(buildDisposeHelper(CGM, blockInfo)); + llvm::Constant *disposeHelper = buildDisposeHelper(CGM, blockInfo); + elements.add(disposeHelper); + + if (cast<llvm::Function>(copyHelper->getOperand(0))->hasInternalLinkage() || + cast<llvm::Function>(disposeHelper->getOperand(0)) + ->hasInternalLinkage()) + hasInternalHelper = true; } // Signature. Mandatory ObjC-style method descriptor @encode sequence. @@ -134,12 +256,26 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, if (C.getLangOpts().OpenCL) AddrSpace = C.getTargetAddressSpace(LangAS::opencl_constant); + llvm::GlobalValue::LinkageTypes linkage; + if (descName.empty()) { + linkage = llvm::GlobalValue::InternalLinkage; + descName = "__block_descriptor_tmp"; + } else if (hasInternalHelper) { + // If either the copy helper or the dispose helper has internal linkage, + // the block descriptor must have internal linkage too. + linkage = llvm::GlobalValue::InternalLinkage; + } else { + linkage = llvm::GlobalValue::LinkOnceODRLinkage; + } + llvm::GlobalVariable *global = - elements.finishAndCreateGlobal("__block_descriptor_tmp", - CGM.getPointerAlign(), - /*constant*/ true, - llvm::GlobalValue::InternalLinkage, - AddrSpace); + elements.finishAndCreateGlobal(descName, CGM.getPointerAlign(), + /*constant*/ true, linkage, AddrSpace); + + if (linkage == llvm::GlobalValue::LinkOnceODRLinkage) { + global->setVisibility(llvm::GlobalValue::HiddenVisibility); + global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + } return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType()); } @@ -1510,39 +1646,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, return fn; } -namespace { - -/// Represents a type of copy/destroy operation that should be performed for an -/// entity that's captured by a block. -enum class BlockCaptureEntityKind { - CXXRecord, // Copy or destroy - ARCWeak, - ARCStrong, - NonTrivialCStruct, - BlockObject, // Assign or release - None -}; - -/// Represents a captured entity that requires extra operations in order for -/// this entity to be copied or destroyed correctly. -struct BlockCaptureManagedEntity { - BlockCaptureEntityKind Kind; - BlockFieldFlags Flags; - const BlockDecl::Capture *CI; - const CGBlockInfo::Capture *Capture; - - BlockCaptureManagedEntity(BlockCaptureEntityKind Type, BlockFieldFlags Flags, - const BlockDecl::Capture &CI, - const CGBlockInfo::Capture &Capture) - : Kind(Type), Flags(Flags), CI(&CI), Capture(&Capture) {} - - bool operator<(const BlockCaptureManagedEntity &Other) const { - return Capture->getOffset() < Other.Capture->getOffset(); - } -}; - -} // end anonymous namespace - static std::pair<BlockCaptureEntityKind, BlockFieldFlags> computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, const LangOptions &LangOpts) { @@ -1600,22 +1703,29 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, llvm_unreachable("after exhaustive PrimitiveCopyKind switch"); } +static std::pair<BlockCaptureEntityKind, BlockFieldFlags> +computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, + const LangOptions &LangOpts); + /// Find the set of block captures that need to be explicitly copied or destroy. static void findBlockCapturedManagedEntities( const CGBlockInfo &BlockInfo, const LangOptions &LangOpts, - SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures, - llvm::function_ref<std::pair<BlockCaptureEntityKind, BlockFieldFlags>( - const BlockDecl::Capture &, QualType, const LangOptions &)> - Predicate) { + SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures) { for (const auto &CI : BlockInfo.getBlockDecl()->captures()) { const VarDecl *Variable = CI.getVariable(); const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable); if (Capture.isConstant()) continue; - auto Info = Predicate(CI, Variable->getType(), LangOpts); - if (Info.first != BlockCaptureEntityKind::None) - ManagedCaptures.emplace_back(Info.first, Info.second, CI, Capture); + auto CopyInfo = + computeCopyInfoForBlockCapture(CI, Variable->getType(), LangOpts); + auto DisposeInfo = + computeDestroyInfoForBlockCapture(CI, Variable->getType(), LangOpts); + if (CopyInfo.first != BlockCaptureEntityKind::None || + DisposeInfo.first != BlockCaptureEntityKind::None) + ManagedCaptures.emplace_back(CopyInfo.first, DisposeInfo.first, + CopyInfo.second, DisposeInfo.second, CI, + Capture); } // Sort the captures by offset. @@ -1656,15 +1766,114 @@ bool CodeGenFunction::cxxDestructorCanThrow(QualType T) { return false; } -static std::string getCopyDestroyHelperFuncName( - const SmallVectorImpl<BlockCaptureManagedEntity> &Captures, - CharUnits BlockAlignment, bool IsCopyHelper, CodeGenModule &CGM) { +// Return a string that has the information about a capture. +static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, + CaptureStrKind StrKind, + CharUnits BlockAlignment, + CodeGenModule &CGM) { + std::string Str; ASTContext &Ctx = CGM.getContext(); std::unique_ptr<ItaniumMangleContext> MC( ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())); + const BlockDecl::Capture &CI = *E.CI; + QualType CaptureTy = CI.getVariable()->getType(); - std::string Name = - IsCopyHelper ? "__copy_helper_block_" : "__destroy_helper_block_"; + BlockCaptureEntityKind Kind; + BlockFieldFlags Flags; + + // CaptureStrKind::Merged should be passed only when the operations and the + // flags are the same for copy and dispose. + assert((StrKind != CaptureStrKind::Merged || + (E.CopyKind == E.DisposeKind && E.CopyFlags == E.DisposeFlags)) && + "different operations and flags"); + + if (StrKind == CaptureStrKind::DisposeHelper) { + Kind = E.DisposeKind; + Flags = E.DisposeFlags; + } else { + Kind = E.CopyKind; + Flags = E.CopyFlags; + } + + switch (Kind) { + case BlockCaptureEntityKind::CXXRecord: { + Str += "c"; + SmallString<256> TyStr; + llvm::raw_svector_ostream Out(TyStr); + MC->mangleTypeName(CaptureTy, Out); + Str += llvm::to_string(TyStr.size()) + TyStr.c_str(); + break; + } + case BlockCaptureEntityKind::ARCWeak: + Str += "w"; + break; + case BlockCaptureEntityKind::ARCStrong: + Str += "s"; + break; + case BlockCaptureEntityKind::BlockObject: { + const VarDecl *Var = CI.getVariable(); + unsigned F = Flags.getBitMask(); + if (F & BLOCK_FIELD_IS_BYREF) { + Str += "r"; + if (F & BLOCK_FIELD_IS_WEAK) + Str += "w"; + else { + // If CaptureStrKind::Merged is passed, check both the copy expression + // and the destructor. + if (StrKind != CaptureStrKind::DisposeHelper) { + if (Ctx.getBlockVarCopyInit(Var).canThrow()) + Str += "c"; + } + if (StrKind != CaptureStrKind::CopyHelper) { + if (CodeGenFunction::cxxDestructorCanThrow(CaptureTy)) + Str += "d"; + } + } + } else { + assert((F & BLOCK_FIELD_IS_OBJECT) && "unexpected flag value"); + if (F == BLOCK_FIELD_IS_BLOCK) + Str += "b"; + else + Str += "o"; + } + break; + } + case BlockCaptureEntityKind::NonTrivialCStruct: { + bool IsVolatile = CaptureTy.isVolatileQualified(); + CharUnits Alignment = + BlockAlignment.alignmentAtOffset(E.Capture->getOffset()); + + Str += "n"; + std::string FuncStr; + if (StrKind == CaptureStrKind::DisposeHelper) + FuncStr = CodeGenFunction::getNonTrivialDestructorStr( + CaptureTy, Alignment, IsVolatile, Ctx); + else + // If CaptureStrKind::Merged is passed, use the copy constructor string. + // It has all the information that the destructor string has. + FuncStr = CodeGenFunction::getNonTrivialCopyConstructorStr( + CaptureTy, Alignment, IsVolatile, Ctx); + // The underscore is necessary here because non-trivial copy constructor + // and destructor strings can start with a number. + Str += llvm::to_string(FuncStr.size()) + "_" + FuncStr; + break; + } + case BlockCaptureEntityKind::None: + break; + } + + return Str; +} + +static std::string getCopyDestroyHelperFuncName( + const SmallVectorImpl<BlockCaptureManagedEntity> &Captures, + CharUnits BlockAlignment, CaptureStrKind StrKind, CodeGenModule &CGM) { + assert((StrKind == CaptureStrKind::CopyHelper || + StrKind == CaptureStrKind::DisposeHelper) && + "unexpected CaptureStrKind"); + std::string Name = StrKind == CaptureStrKind::CopyHelper + ? "__copy_helper_block_" + : "__destroy_helper_block_"; if (CGM.getLangOpts().Exceptions) Name += "e"; if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions) @@ -1672,72 +1881,8 @@ static std::string getCopyDestroyHelperFuncName( Name += llvm::to_string(BlockAlignment.getQuantity()) + "_"; for (const BlockCaptureManagedEntity &E : Captures) { - const BlockDecl::Capture &CI = *E.CI; - BlockFieldFlags Flags = E.Flags; - QualType CaptureTy = CI.getVariable()->getType(); Name += llvm::to_string(E.Capture->getOffset().getQuantity()); - - switch (E.Kind) { - case BlockCaptureEntityKind::CXXRecord: { - Name += "c"; - SmallString<256> Str; - llvm::raw_svector_ostream Out(Str); - MC->mangleTypeName(CaptureTy, Out); - Name += llvm::to_string(Str.size()) + Str.c_str(); - break; - } - case BlockCaptureEntityKind::ARCWeak: - Name += "w"; - break; - case BlockCaptureEntityKind::ARCStrong: - Name += "s"; - break; - case BlockCaptureEntityKind::BlockObject: { - const VarDecl *Var = CI.getVariable(); - unsigned F = Flags.getBitMask(); - if (F & BLOCK_FIELD_IS_BYREF) { - Name += "r"; - if (F & BLOCK_FIELD_IS_WEAK) - Name += "w"; - else { - if (IsCopyHelper) { - if (Ctx.getBlockVarCopyInit(Var).canThrow()) - Name += "c"; - } else { - if (CodeGenFunction::cxxDestructorCanThrow(CaptureTy)) - Name += "d"; - } - } - } else { - assert((F & BLOCK_FIELD_IS_OBJECT) && "unexpected flag value"); - if (F == BLOCK_FIELD_IS_BLOCK) - Name += "b"; - else - Name += "o"; - } - break; - } - case BlockCaptureEntityKind::NonTrivialCStruct: { - bool IsVolatile = CaptureTy.isVolatileQualified(); - CharUnits Alignment = - BlockAlignment.alignmentAtOffset(E.Capture->getOffset()); - - Name += "n"; - std::string Str; - if (IsCopyHelper) - Str = CodeGenFunction::getNonTrivialCopyConstructorStr( - CaptureTy, Alignment, IsVolatile, Ctx); - else - Str = CodeGenFunction::getNonTrivialDestructorStr(CaptureTy, Alignment, - IsVolatile, Ctx); - // The underscore is necessary here because non-trivial copy constructor - // and destructor strings can start with a number. - Name += llvm::to_string(Str.size()) + "_" + Str; - break; - } - case BlockCaptureEntityKind::None: - llvm_unreachable("unexpected block capture kind"); - } + Name += getBlockCaptureStr(E, StrKind, BlockAlignment, CGM); } return Name; @@ -1781,7 +1926,7 @@ static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind, break; } case BlockCaptureEntityKind::None: - llvm_unreachable("unexpected BlockCaptureEntityKind"); + break; } } @@ -1809,11 +1954,10 @@ static void setBlockHelperAttributesVisibility(bool CapturesNonExternalType, llvm::Constant * CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures; - findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures, - computeCopyInfoForBlockCapture); + findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures); std::string FuncName = getCopyDestroyHelperFuncName(CopiedCaptures, blockInfo.BlockAlign, - /*IsCopyHelper*/ true, CGM); + CaptureStrKind::CopyHelper, CGM); if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName)) return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy); @@ -1868,13 +2012,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { const BlockDecl::Capture &CI = *CopiedCapture.CI; const CGBlockInfo::Capture &capture = *CopiedCapture.Capture; QualType captureType = CI.getVariable()->getType(); - BlockFieldFlags flags = CopiedCapture.Flags; + BlockFieldFlags flags = CopiedCapture.CopyFlags; unsigned index = capture.getIndex(); Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset()); Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset()); - switch (CopiedCapture.Kind) { + switch (CopiedCapture.CopyKind) { case BlockCaptureEntityKind::CXXRecord: // If there's an explicit copy expression, we do that. assert(CI.getCopyExpr() && "copy expression for variable is missing"); @@ -1932,12 +2076,12 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { break; } case BlockCaptureEntityKind::None: - llvm_unreachable("unexpected BlockCaptureEntityKind"); + continue; } // Ensure that we destroy the copied object if an exception is thrown later // in the helper function. - pushCaptureCleanup(CopiedCapture.Kind, dstField, captureType, flags, + pushCaptureCleanup(CopiedCapture.CopyKind, dstField, captureType, flags, /*ForCopyHelper*/ true, CI.getVariable(), *this); } @@ -2003,11 +2147,10 @@ computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, llvm::Constant * CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures; - findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures, - computeDestroyInfoForBlockCapture); + findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures); std::string FuncName = getCopyDestroyHelperFuncName(DestroyedCaptures, blockInfo.BlockAlign, - /*IsCopyHelper*/ false, CGM); + CaptureStrKind::DisposeHelper, CGM); if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName)) return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy); @@ -2057,12 +2200,12 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { for (const auto &DestroyedCapture : DestroyedCaptures) { const BlockDecl::Capture &CI = *DestroyedCapture.CI; const CGBlockInfo::Capture &capture = *DestroyedCapture.Capture; - BlockFieldFlags flags = DestroyedCapture.Flags; + BlockFieldFlags flags = DestroyedCapture.DisposeFlags; Address srcField = Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset()); - pushCaptureCleanup(DestroyedCapture.Kind, srcField, + pushCaptureCleanup(DestroyedCapture.DisposeKind, srcField, CI.getVariable()->getType(), flags, /*ForCopyHelper*/ false, CI.getVariable(), *this); } diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h index 402acea70e7..c802948af06 100644 --- a/clang/lib/CodeGen/CGBlocks.h +++ b/clang/lib/CodeGen/CGBlocks.h @@ -132,6 +132,9 @@ public: friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) { return (l.flags & r.flags); } + bool operator==(BlockFieldFlags Other) const { + return flags == Other.flags; + } }; inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) { return BlockFieldFlags(l) | BlockFieldFlags(r); diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 2b54e7bd67a..92e442d3312 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -37,6 +37,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include <cstdio> @@ -1085,9 +1086,14 @@ public: const CGBlockInfo &blockInfo) override; llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, const CGBlockInfo &blockInfo) override; + std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM, + const CGBlockInfo &blockInfo) override; llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM, QualType T) override; + +private: + void fillRunSkipBlockVars(CodeGenModule &CGM, const CGBlockInfo &blockInfo); }; namespace { @@ -2795,8 +2801,44 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { return getConstantGEP(VMContext, Entry, 0, 0); } -llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, - const CGBlockInfo &blockInfo) { +static std::string getBlockLayoutInfoString( + const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> &RunSkipBlockVars, + bool HasCopyDisposeHelpers) { + std::string Str; + for (const CGObjCCommonMac::RUN_SKIP &R : RunSkipBlockVars) { + if (R.opcode == CGObjCCommonMac::BLOCK_LAYOUT_UNRETAINED) { + // Copy/dispose helpers don't have any information about + // __unsafe_unretained captures, so unconditionally concatenate a string. + Str += "u"; + } else if (HasCopyDisposeHelpers) { + // Information about __strong, __weak, or byref captures has already been + // encoded into the names of the copy/dispose helpers. We have to add a + // string here only when the copy/dispose helpers aren't generated (which + // happens when the block is non-escaping). + continue; + } else { + switch (R.opcode) { + case CGObjCCommonMac::BLOCK_LAYOUT_STRONG: + Str += "s"; + break; + case CGObjCCommonMac::BLOCK_LAYOUT_BYREF: + Str += "r"; + break; + case CGObjCCommonMac::BLOCK_LAYOUT_WEAK: + Str += "w"; + break; + default: + continue; + } + } + Str += llvm::to_string(R.block_var_bytepos.getQuantity()); + Str += "l" + llvm::to_string(R.block_var_size.getQuantity()); + } + return Str; +} + +void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); RunSkipBlockVars.clear(); @@ -2845,9 +2887,22 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false), fieldOffset, fieldSize); } +} + +llvm::Constant * +CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + fillRunSkipBlockVars(CGM, blockInfo); return getBitmapBlockLayout(false); } +std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + fillRunSkipBlockVars(CGM, blockInfo); + return getBlockLayoutInfoString(RunSkipBlockVars, + blockInfo.needsCopyDisposeHelpers()); +} + llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM, QualType T) { assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 78d5aba4128..fa16c198adb 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -278,6 +278,10 @@ public: const CodeGen::CGBlockInfo &blockInfo) = 0; virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, const CodeGen::CGBlockInfo &blockInfo) = 0; + virtual std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + return {}; + } /// Returns an i8* which points to the byref layout information. virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM, |