diff options
| author | 2019-01-27 16:42:12 +0000 | |
|---|---|---|
| committer | 2019-01-27 16:42:12 +0000 | |
| commit | b773203fb58f3ef282fb69c832d8710cab5bc82d (patch) | |
| tree | e75913f147570fbd75169647b144df85b88a038c /gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp | |
| parent | tweak errno in previous (diff) | |
| download | wireguard-openbsd-b773203fb58f3ef282fb69c832d8710cab5bc82d.tar.xz wireguard-openbsd-b773203fb58f3ef282fb69c832d8710cab5bc82d.zip | |
Import LLVM 7.0.1 release including clang, lld and lldb.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp')
| -rw-r--r-- | gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp | 559 |
1 files changed, 318 insertions, 241 deletions
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp index 5f73d4cf791..906b98bfbaf 100644 --- a/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp +++ b/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp @@ -66,7 +66,7 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM, /// 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. -/// Its definition will have 4 (or optinally 6) words. +/// Its definition will have 4 (or optionally 6) words. /// \code /// struct Block_descriptor { /// unsigned long reserved; @@ -85,7 +85,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, cast<llvm::IntegerType>(CGM.getTypes().ConvertType(C.UnsignedLongTy)); llvm::PointerType *i8p = nullptr; if (CGM.getLangOpts().OpenCL) - i8p = + i8p = llvm::Type::getInt8PtrTy( CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant)); else @@ -104,7 +104,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, elements.addInt(ulong, blockInfo.BlockSize.getQuantity()); // Optional copy/dispose helpers. - if (blockInfo.NeedsCopyDispose) { + if (blockInfo.needsCopyDisposeHelpers()) { // copy_func_helper_decl elements.add(buildCopyHelper(CGM, blockInfo)); @@ -117,7 +117,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr()); elements.add(llvm::ConstantExpr::getBitCast( CGM.GetAddrOfConstantCString(typeAtEncoding).getPointer(), i8p)); - + // GC layout. if (C.getLangOpts().ObjC1) { if (CGM.getLangOpts().getGC() != LangOptions::NonGC) @@ -159,6 +159,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, /// These are the flags (with corresponding bit number) that the /// compiler is actually supposed to know about. + /// 23. BLOCK_IS_NOESCAPE - indicates that the block is non-escaping /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block /// descriptor provides copy and dispose helper functions /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured @@ -307,25 +308,12 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, assert(elementTypes.empty()); if (CGM.getLangOpts().OpenCL) { - // The header is basically 'struct { int; int; generic void *; + // The header is basically 'struct { int; int; // custom_fields; }'. Assert that struct is packed. - auto GenericAS = - CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic); - auto GenPtrAlign = - CharUnits::fromQuantity(CGM.getTarget().getPointerAlign(GenericAS) / 8); - auto GenPtrSize = - CharUnits::fromQuantity(CGM.getTarget().getPointerWidth(GenericAS) / 8); - assert(CGM.getIntSize() <= GenPtrSize); - assert(CGM.getIntAlign() <= GenPtrAlign); - assert((2 * CGM.getIntSize()).isMultipleOf(GenPtrAlign)); elementTypes.push_back(CGM.IntTy); /* total size */ elementTypes.push_back(CGM.IntTy); /* align */ - elementTypes.push_back( - CGM.getOpenCLRuntime() - .getGenericVoidPointerType()); /* invoke function */ - unsigned Offset = - 2 * CGM.getIntSize().getQuantity() + GenPtrSize.getQuantity(); - unsigned BlockAlign = GenPtrAlign.getQuantity(); + unsigned Offset = 2 * CGM.getIntSize().getQuantity(); + unsigned BlockAlign = CGM.getIntAlign().getQuantity(); if (auto *Helper = CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { for (auto I : Helper->getCustomFieldTypes()) /* custom fields */ { @@ -343,7 +331,7 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, info.BlockSize = CharUnits::fromQuantity(Offset); } else { // The header is basically 'struct { void *; int; int; void *; void *; }'. - // Assert that that struct is packed. + // Assert that the struct is packed. assert(CGM.getIntSize() <= CGM.getPointerSize()); assert(CGM.getIntAlign() <= CGM.getPointerAlign()); assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign())); @@ -393,7 +381,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, else if (C.getLangOpts().ObjC1 && CGM.getLangOpts().getGC() == LangOptions::NonGC) info.HasCapturedVariableLayout = true; - + // Collect the layout chunks. SmallVector<BlockLayoutChunk, 16> layout; layout.reserve(block->capturesCXXThis() + @@ -477,6 +465,14 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, info.NeedsCopyDispose = true; info.HasCXXObject = true; + // So do C structs that require non-trivial copy construction or + // destruction. + } else if (variable->getType().isNonTrivialToPrimitiveCopy() == + QualType::PCK_Struct || + variable->getType().isDestructedType() == + QualType::DK_nontrivial_c_struct) { + info.NeedsCopyDispose = true; + // And so do types with destructors. } else if (CGM.getLangOpts().CPlusPlus) { if (const CXXRecordDecl *record = @@ -491,12 +487,12 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, QualType VT = getCaptureFieldType(*CGF, CI); CharUnits size = C.getTypeSizeInChars(VT); CharUnits align = C.getDeclAlign(variable); - + maxFieldAlign = std::max(maxFieldAlign, align); llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(VT); - + layout.push_back( BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT)); } @@ -513,11 +509,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, // to get reproducible results. There should probably be an // llvm::array_pod_stable_sort. std::stable_sort(layout.begin(), layout.end()); - + // Needed for blocks layout info. info.BlockHeaderForcedGapOffset = info.BlockSize; info.BlockHeaderForcedGapSize = CharUnits::Zero(); - + CharUnits &blockSize = info.BlockSize; info.BlockAlign = std::max(maxFieldAlign, info.BlockAlign); @@ -568,7 +564,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, } assert(endAlign == getLowBit(blockSize)); - + // At this point, we just have to add padding if the end align still // isn't aligned right. if (endAlign < maxFieldAlign) { @@ -689,7 +685,7 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { CleanupKind cleanupKind = InactiveNormalCleanup; bool useArrayEHCleanup = CGF.needsEHCleanup(dtorKind); - if (useArrayEHCleanup) + if (useArrayEHCleanup) cleanupKind = InactiveNormalAndEHCleanup; CGF.pushDestroy(cleanupKind, addr, VT, @@ -705,11 +701,8 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { /// kind of cleanup object is a BlockDecl*. void CodeGenFunction::enterNonTrivialFullExpression(const ExprWithCleanups *E) { assert(E->getNumObjects() != 0); - ArrayRef<ExprWithCleanups::CleanupObject> cleanups = E->getObjects(); - for (ArrayRef<ExprWithCleanups::CleanupObject>::iterator - i = cleanups.begin(), e = cleanups.end(); i != e; ++i) { - enterBlockScope(*this, *i); - } + for (const ExprWithCleanups::CleanupObject &C : E->getObjects()) + enterBlockScope(*this, C); } /// Find the layout for the given block in a linked list and remove it. @@ -740,27 +733,19 @@ void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) { } /// Emit a block literal expression in the current function. -llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr, - llvm::Function **InvokeF) { +llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { // If the block has no captures, we won't have a pre-computed // layout for it. if (!blockExpr->getBlockDecl()->hasCaptures()) { // The block literal is emitted as a global variable, and the block invoke // function has to be extracted from its initializer. if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr)) { - if (InvokeF) { - auto *GV = cast<llvm::GlobalVariable>( - cast<llvm::Constant>(Block)->stripPointerCasts()); - auto *BlockInit = cast<llvm::ConstantStruct>(GV->getInitializer()); - *InvokeF = cast<llvm::Function>( - BlockInit->getAggregateElement(2)->stripPointerCasts()); - } return Block; } CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName()); computeBlockInfo(CGM, this, blockInfo); blockInfo.BlockExpression = blockExpr; - return EmitBlockLiteral(blockInfo, InvokeF); + return EmitBlockLiteral(blockInfo); } // Find the block info for this block and take ownership of it. @@ -769,28 +754,17 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr, blockExpr->getBlockDecl())); blockInfo->BlockExpression = blockExpr; - return EmitBlockLiteral(*blockInfo, InvokeF); + return EmitBlockLiteral(*blockInfo); } -llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, - llvm::Function **InvokeF) { +llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL; - auto GenVoidPtrTy = - IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy; - LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default; - auto GenVoidPtrSize = CharUnits::fromQuantity( - CGM.getTarget().getPointerWidth( - CGM.getContext().getTargetAddressSpace(GenVoidPtrAddr)) / - 8); // Using the computed layout, generate the actual block function. bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda(); CodeGenFunction BlockCGF{CGM, true}; BlockCGF.SanOpts = SanOpts; auto *InvokeFn = BlockCGF.GenerateBlockFunction( CurGD, blockInfo, LocalDeclMap, isLambdaConv, blockInfo.CanBeGlobal); - if (InvokeF) - *InvokeF = InvokeFn; - auto *blockFn = llvm::ConstantExpr::getPointerCast(InvokeFn, GenVoidPtrTy); // If there is nothing to capture, we can emit this as a global block. if (blockInfo.CanBeGlobal) @@ -805,8 +779,13 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, llvm::Constant *descriptor; BlockFlags flags; if (!IsOpenCL) { - isa = llvm::ConstantExpr::getBitCast(CGM.getNSConcreteStackBlock(), - VoidPtrTy); + // If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock + // and set the BLOCK_IS_GLOBAL bit of field 'flags'. Copying a non-escaping + // block just returns the original block and releasing it is a no-op. + llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape() + ? CGM.getNSConcreteGlobalBlock() + : CGM.getNSConcreteStackBlock(); + isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy); // Build the block descriptor. descriptor = buildBlockDescriptor(CGM, blockInfo); @@ -815,12 +794,14 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, flags = BLOCK_HAS_SIGNATURE; if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT; - if (blockInfo.NeedsCopyDispose) + if (blockInfo.needsCopyDisposeHelpers()) flags |= BLOCK_HAS_COPY_DISPOSE; if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; + if (blockInfo.getBlockDecl()->doesNotEscape()) + flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL; } auto projectField = @@ -859,11 +840,12 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()), getIntSize(), "block.align"); } - addHeaderField(blockFn, GenVoidPtrSize, "block.invoke"); - if (!IsOpenCL) + if (!IsOpenCL) { + addHeaderField(llvm::ConstantExpr::getBitCast(InvokeFn, VoidPtrTy), + getPointerSize(), "block.invoke"); addHeaderField(descriptor, getPointerSize(), "block.descriptor"); - else if (auto *Helper = - CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { + } else if (auto *Helper = + CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) { addHeaderField( I.first, @@ -913,7 +895,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, const CGBlockInfo::Capture &enclosingCapture = BlockInfo->getCapture(variable); - // This is a [[type]]*, except that a byref entry wil just be an i8**. + // This is a [[type]]*, except that a byref entry will just be an i8**. src = Builder.CreateStructGEP(LoadBlockStruct(), enclosingCapture.getIndex(), enclosingCapture.getOffset(), @@ -955,7 +937,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, AggValueSlot::forAddr(blockField, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased); + AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap); EmitAggExpr(copyExpr, Slot); } else { EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr); @@ -1024,6 +1007,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, llvm::Value *result = Builder.CreatePointerCast( blockAddr.getPointer(), ConvertType(blockInfo.getBlockExpr()->getType())); + if (IsOpenCL) { + CGM.getOpenCLRuntime().recordBlockInfo(blockInfo.BlockExpression, InvokeFn, + result); + } + return result; } @@ -1061,38 +1049,23 @@ llvm::Type *CodeGenModule::getBlockDescriptorType() { } llvm::Type *CodeGenModule::getGenericBlockLiteralType() { + assert(!getLangOpts().OpenCL && "OpenCL does not need this"); + if (GenericBlockLiteralType) return GenericBlockLiteralType; llvm::Type *BlockDescPtrTy = getBlockDescriptorType(); - if (getLangOpts().OpenCL) { - // struct __opencl_block_literal_generic { - // int __size; - // int __align; - // __generic void *__invoke; - // /* custom fields */ - // }; - SmallVector<llvm::Type *, 8> StructFields( - {IntTy, IntTy, getOpenCLRuntime().getGenericVoidPointerType()}); - if (auto *Helper = getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { - for (auto I : Helper->getCustomFieldTypes()) - StructFields.push_back(I); - } - GenericBlockLiteralType = llvm::StructType::create( - StructFields, "struct.__opencl_block_literal_generic"); - } else { - // struct __block_literal_generic { - // void *__isa; - // int __flags; - // int __reserved; - // void (*__invoke)(void *); - // struct __block_descriptor *__descriptor; - // }; - GenericBlockLiteralType = - llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy, - IntTy, IntTy, VoidPtrTy, BlockDescPtrTy); - } + // struct __block_literal_generic { + // void *__isa; + // int __flags; + // int __reserved; + // void (*__invoke)(void *); + // struct __block_descriptor *__descriptor; + // }; + GenericBlockLiteralType = + llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy, + IntTy, IntTy, VoidPtrTy, BlockDescPtrTy); return GenericBlockLiteralType; } @@ -1103,27 +1076,21 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, E->getCallee()->getType()->getAs<BlockPointerType>(); llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee()); + llvm::Value *FuncPtr; - // Get a pointer to the generic block literal. - // For OpenCL we generate generic AS void ptr to be able to reuse the same - // block definition for blocks with captures generated as private AS local - // variables and without captures generated as global AS program scope - // variables. - unsigned AddrSpace = 0; - if (getLangOpts().OpenCL) - AddrSpace = getContext().getTargetAddressSpace(LangAS::opencl_generic); - - llvm::Type *BlockLiteralTy = - llvm::PointerType::get(CGM.getGenericBlockLiteralType(), AddrSpace); + if (!CGM.getLangOpts().OpenCL) { + // Get a pointer to the generic block literal. + llvm::Type *BlockLiteralTy = + llvm::PointerType::get(CGM.getGenericBlockLiteralType(), 0); - // Bitcast the callee to a block literal. - BlockPtr = - Builder.CreatePointerCast(BlockPtr, BlockLiteralTy, "block.literal"); + // Bitcast the callee to a block literal. + BlockPtr = + Builder.CreatePointerCast(BlockPtr, BlockLiteralTy, "block.literal"); - // Get the function pointer from the literal. - llvm::Value *FuncPtr = - Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, - CGM.getLangOpts().OpenCL ? 2 : 3); + // Get the function pointer from the literal. + FuncPtr = + Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, 3); + } // Add the block literal. CallArgList Args; @@ -1146,7 +1113,11 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, EmitCallArgs(Args, FnType->getAs<FunctionProtoType>(), E->arguments()); // Load the function. - llvm::Value *Func = Builder.CreateAlignedLoad(FuncPtr, getPointerAlign()); + llvm::Value *Func; + if (CGM.getLangOpts().OpenCL) + Func = CGM.getOpenCLRuntime().getInvokeFunction(E->getCallee()); + else + Func = Builder.CreateAlignedLoad(FuncPtr, getPointerAlign()); const FunctionType *FuncTy = FnType->castAs<FunctionType>(); const CGFunctionInfo &FnInfo = @@ -1242,9 +1213,13 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, auto fields = builder.beginStruct(); bool IsOpenCL = CGM.getLangOpts().OpenCL; + bool IsWindows = CGM.getTarget().getTriple().isOSWindows(); if (!IsOpenCL) { // isa - fields.add(CGM.getNSConcreteGlobalBlock()); + if (IsWindows) + fields.addNullPointer(CGM.Int8PtrPtrTy); + else + fields.add(CGM.getNSConcreteGlobalBlock()); // __flags BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; @@ -1255,14 +1230,14 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, // Reserved fields.addInt(CGM.IntTy, 0); + + // Function + fields.add(blockFn); } else { fields.addInt(CGM.IntTy, blockInfo.BlockSize.getQuantity()); fields.addInt(CGM.IntTy, blockInfo.BlockAlign.getQuantity()); } - // Function - fields.add(blockFn); - if (!IsOpenCL) { // Descriptor fields.add(buildBlockDescriptor(CGM, blockInfo)); @@ -1279,7 +1254,27 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, llvm::Constant *literal = fields.finishAndCreateGlobal( "__block_literal_global", blockInfo.BlockAlign, - /*constant*/ true, llvm::GlobalVariable::InternalLinkage, AddrSpace); + /*constant*/ !IsWindows, llvm::GlobalVariable::InternalLinkage, AddrSpace); + + // Windows does not allow globals to be initialised to point to globals in + // different DLLs. Any such variables must run code to initialise them. + if (IsWindows) { + auto *Init = llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, + {}), llvm::GlobalValue::InternalLinkage, ".block_isa_init", + &CGM.getModule()); + llvm::IRBuilder<> b(llvm::BasicBlock::Create(CGM.getLLVMContext(), "entry", + Init)); + b.CreateAlignedStore(CGM.getNSConcreteGlobalBlock(), + b.CreateStructGEP(literal, 0), CGM.getPointerAlign().getQuantity()); + b.CreateRetVoid(); + // We can't use the normal LLVM global initialisation array, because we + // need to specify that this runs early in library initialisation. + auto *InitVar = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + /*isConstant*/true, llvm::GlobalValue::InternalLinkage, + Init, ".block_isa_init_ptr"); + InitVar->setSection(".CRT$XCLa"); + CGM.addUsedGlobal(InitVar); + } // Return a constant of the appropriately-casted type. llvm::Type *RequiredType = @@ -1287,6 +1282,10 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, llvm::Constant *Result = llvm::ConstantExpr::getPointerCast(literal, RequiredType); CGM.setAddrOfGlobalBlock(blockInfo.BlockExpression, Result); + if (CGM.getContext().getLangOpts().OpenCL) + CGM.getOpenCLRuntime().recordBlockInfo( + blockInfo.BlockExpression, + cast<llvm::Function>(blockFn->stripPointerCasts()), Result); return Result; } @@ -1340,7 +1339,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, CurGD = GD; CurEHLocation = blockInfo.getBlockExpr()->getLocEnd(); - + BlockInfo = &blockInfo; // Arrange for local static and local extern declarations to appear @@ -1479,8 +1478,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { auto addr = LocalDeclMap.find(variable)->second; - DI->EmitDeclareOfAutoVariable(variable, addr.getPointer(), - Builder); + (void)DI->EmitDeclareOfAutoVariable(variable, addr.getPointer(), + Builder); continue; } @@ -1513,6 +1512,7 @@ enum class BlockCaptureEntityKind { CXXRecord, // Copy or destroy ARCWeak, ARCStrong, + NonTrivialCStruct, BlockObject, // Assign or release None }; @@ -1548,39 +1548,46 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, Flags |= BLOCK_FIELD_IS_WEAK; return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); } - if (!T->isObjCRetainableType()) - // For all other types, the memcpy is fine. - return std::make_pair(BlockCaptureEntityKind::None, Flags); Flags = BLOCK_FIELD_IS_OBJECT; bool isBlockPointer = T->isBlockPointerType(); if (isBlockPointer) Flags = BLOCK_FIELD_IS_BLOCK; - // Special rules for ARC captures: - Qualifiers QS = T.getQualifiers(); - - // We need to register __weak direct captures with the runtime. - if (QS.getObjCLifetime() == Qualifiers::OCL_Weak) + switch (T.isNonTrivialToPrimitiveCopy()) { + case QualType::PCK_Struct: + return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct, + BlockFieldFlags()); + case QualType::PCK_ARCWeak: + // We need to register __weak direct captures with the runtime. return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags); - - // We need to retain the copied value for __strong direct captures. - if (QS.getObjCLifetime() == Qualifiers::OCL_Strong) { - // If it's a block pointer, we have to copy the block and - // assign that to the destination pointer, so we might as - // well use _Block_object_assign. Otherwise we can avoid that. + case QualType::PCK_ARCStrong: + // We need to retain the copied value for __strong direct captures. + // If it's a block pointer, we have to copy the block and assign that to + // the destination pointer, so we might as well use _Block_object_assign. + // Otherwise we can avoid that. return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong : BlockCaptureEntityKind::BlockObject, Flags); - } + case QualType::PCK_Trivial: + case QualType::PCK_VolatileTrivial: { + if (!T->isObjCRetainableType()) + // For all other types, the memcpy is fine. + return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); - // Non-ARC captures of retainable pointers are strong and - // therefore require a call to _Block_object_assign. - if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount) - return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); + // Special rules for ARC captures: + Qualifiers QS = T.getQualifiers(); + + // Non-ARC captures of retainable pointers are strong and + // therefore require a call to _Block_object_assign. + if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount) + return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); - // Otherwise the memcpy is fine. - return std::make_pair(BlockCaptureEntityKind::None, Flags); + // Otherwise the memcpy is fine. + return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); + } + } + llvm_unreachable("after exhaustive PrimitiveCopyKind switch"); } /// Find the set of block captures that need to be explicitly copied or destroy. @@ -1602,6 +1609,64 @@ static void findBlockCapturedManagedEntities( } } +namespace { +/// Release a __block variable. +struct CallBlockRelease final : EHScopeStack::Cleanup { + Address Addr; + BlockFieldFlags FieldFlags; + bool LoadBlockVarAddr; + + CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue) + : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue) {} + + void Emit(CodeGenFunction &CGF, Flags flags) override { + llvm::Value *BlockVarAddr; + if (LoadBlockVarAddr) { + BlockVarAddr = CGF.Builder.CreateLoad(Addr); + BlockVarAddr = CGF.Builder.CreateBitCast(BlockVarAddr, CGF.VoidPtrTy); + } else { + BlockVarAddr = Addr.getPointer(); + } + + CGF.BuildBlockRelease(BlockVarAddr, FieldFlags); + } +}; +} // end anonymous namespace + +static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind, + Address Field, QualType CaptureType, + BlockFieldFlags Flags, bool EHOnly, + CodeGenFunction &CGF) { + switch (CaptureKind) { + case BlockCaptureEntityKind::CXXRecord: + case BlockCaptureEntityKind::ARCWeak: + case BlockCaptureEntityKind::NonTrivialCStruct: + case BlockCaptureEntityKind::ARCStrong: { + if (CaptureType.isDestructedType() && + (!EHOnly || CGF.needsEHCleanup(CaptureType.isDestructedType()))) { + CodeGenFunction::Destroyer *Destroyer = + CaptureKind == BlockCaptureEntityKind::ARCStrong + ? CodeGenFunction::destroyARCStrongImprecise + : CGF.getDestroyer(CaptureType.isDestructedType()); + CleanupKind Kind = + EHOnly ? EHCleanup + : CGF.getCleanupKind(CaptureType.isDestructedType()); + CGF.pushDestroy(Kind, Field, CaptureType, Destroyer, Kind & EHCleanup); + } + break; + } + case BlockCaptureEntityKind::BlockObject: { + if (!EHOnly || CGF.getLangOpts().Exceptions) { + CleanupKind Kind = EHOnly ? EHCleanup : NormalAndEHCleanup; + CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true); + } + break; + } + case BlockCaptureEntityKind::None: + llvm_unreachable("unexpected BlockCaptureEntityKind"); + } +} + /// Generate the copy-helper function for a block closure object: /// static void block_copy_helper(block_t *dst, block_t *src); /// The runtime will have previously initialized 'dst' by doing a @@ -1644,7 +1709,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { false, false); - CGM.SetInternalFunctionAttributes(nullptr, Fn, FI); + CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); StartFunction(FD, C.VoidTy, Fn, FI, args); ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()}; @@ -1665,6 +1730,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { for (const auto &CopiedCapture : CopiedCaptures) { const BlockDecl::Capture &CI = CopiedCapture.CI; const CGBlockInfo::Capture &capture = CopiedCapture.Capture; + QualType captureType = CI.getVariable()->getType(); BlockFieldFlags flags = CopiedCapture.Flags; unsigned index = capture.getIndex(); @@ -1677,6 +1743,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr()); } else if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCWeak) { EmitARCCopyWeak(dstField, srcField); + // If this is a C struct that requires non-trivial copy construction, emit a + // call to its copy constructor. + } else if (CopiedCapture.Kind == + BlockCaptureEntityKind::NonTrivialCStruct) { + QualType varType = CI.getVariable()->getType(); + callCStructCopyConstructor(MakeAddrLValue(dstField, varType), + MakeAddrLValue(srcField, varType)); } else { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCStrong) { @@ -1695,9 +1768,11 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { } else { EmitARCRetainNonBlock(srcValue); - // We don't need this anymore, so kill it. It's not quite - // worth the annoyance to avoid creating it in the first place. - cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent(); + // Unless EH cleanup is required, we don't need this anymore, so kill + // it. It's not quite worth the annoyance to avoid creating it in the + // first place. + if (!needsEHCleanup(captureType.isDestructedType())) + cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent(); } } else { assert(CopiedCapture.Kind == BlockCaptureEntityKind::BlockObject); @@ -1725,6 +1800,11 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { } } } + + // Ensure that we destroy the copied object if an exception is thrown later + // in the helper function. + pushCaptureCleanup(CopiedCapture.Kind, dstField, captureType, flags, /*EHOnly*/ true, + *this); } FinishFunction(); @@ -1732,50 +1812,51 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); } +static BlockFieldFlags +getBlockFieldFlagsForObjCObjectPointer(const BlockDecl::Capture &CI, + QualType T) { + BlockFieldFlags Flags = BLOCK_FIELD_IS_OBJECT; + if (T->isBlockPointerType()) + Flags = BLOCK_FIELD_IS_BLOCK; + return Flags; +} + static std::pair<BlockCaptureEntityKind, BlockFieldFlags> computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, const LangOptions &LangOpts) { - BlockFieldFlags Flags; if (CI.isByRef()) { - Flags = BLOCK_FIELD_IS_BYREF; + BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF; if (T.isObjCGCWeak()) Flags |= BLOCK_FIELD_IS_WEAK; return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); } - if (const CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { - if (Record->hasTrivialDestructor()) - return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); + switch (T.isDestructedType()) { + case QualType::DK_cxx_destructor: return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags()); - } - - // Other types don't need to be destroy explicitly. - if (!T->isObjCRetainableType()) - return std::make_pair(BlockCaptureEntityKind::None, Flags); - - Flags = BLOCK_FIELD_IS_OBJECT; - if (T->isBlockPointerType()) - Flags = BLOCK_FIELD_IS_BLOCK; - - // Special rules for ARC captures. - Qualifiers QS = T.getQualifiers(); - - // Use objc_storeStrong for __strong direct captures; the - // dynamic tools really like it when we do this. - if (QS.getObjCLifetime() == Qualifiers::OCL_Strong) - return std::make_pair(BlockCaptureEntityKind::ARCStrong, Flags); - - // Support __weak direct captures. - if (QS.getObjCLifetime() == Qualifiers::OCL_Weak) - return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags); - - // Non-ARC captures are strong, and we need to use - // _Block_object_dispose. - if (!QS.hasObjCLifetime() && !LangOpts.ObjCAutoRefCount) - return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); - - // Otherwise, we have nothing to do. - return std::make_pair(BlockCaptureEntityKind::None, Flags); + case QualType::DK_objc_strong_lifetime: + // Use objc_storeStrong for __strong direct captures; the + // dynamic tools really like it when we do this. + return std::make_pair(BlockCaptureEntityKind::ARCStrong, + getBlockFieldFlagsForObjCObjectPointer(CI, T)); + case QualType::DK_objc_weak_lifetime: + // Support __weak direct captures. + return std::make_pair(BlockCaptureEntityKind::ARCWeak, + getBlockFieldFlagsForObjCObjectPointer(CI, T)); + case QualType::DK_nontrivial_c_struct: + return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct, + BlockFieldFlags()); + case QualType::DK_none: { + // Non-ARC captures are strong, and we need to use _Block_object_dispose. + if (T->isObjCRetainableType() && !T.getQualifiers().hasObjCLifetime() && + !LangOpts.ObjCAutoRefCount) + return std::make_pair(BlockCaptureEntityKind::BlockObject, + getBlockFieldFlagsForObjCObjectPointer(CI, T)); + // Otherwise, we have nothing to do. + return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); + } + } + llvm_unreachable("after exhaustive DestructionKind switch"); } /// Generate the destroy-helper function for a block closure object: @@ -1814,7 +1895,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { nullptr, SC_Static, false, false); - CGM.SetInternalFunctionAttributes(nullptr, Fn, FI); + CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); StartFunction(FD, C.VoidTy, Fn, FI, args); ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()}; @@ -1839,29 +1920,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { Address srcField = Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset()); - // If the captured record has a destructor then call it. - if (DestroyedCapture.Kind == BlockCaptureEntityKind::CXXRecord) { - const auto *Dtor = - CI.getVariable()->getType()->getAsCXXRecordDecl()->getDestructor(); - PushDestructorCleanup(Dtor, srcField); - - // If this is a __weak capture, emit the release directly. - } else if (DestroyedCapture.Kind == BlockCaptureEntityKind::ARCWeak) { - EmitARCDestroyWeak(srcField); - - // Destroy strong objects with a call if requested. - } else if (DestroyedCapture.Kind == BlockCaptureEntityKind::ARCStrong) { - EmitARCDestroyStrong(srcField, ARCImpreciseLifetime); - - // Otherwise we call _Block_object_dispose. It wouldn't be too - // hard to just emit this as a cleanup if we wanted to make sure - // that things were done in reverse. - } else { - assert(DestroyedCapture.Kind == BlockCaptureEntityKind::BlockObject); - llvm::Value *value = Builder.CreateLoad(srcField); - value = Builder.CreateBitCast(value, VoidPtrTy); - BuildBlockRelease(value, flags); - } + pushCaptureCleanup(DestroyedCapture.Kind, srcField, + CI.getVariable()->getType(), flags, /*EHOnly*/ false, *this); } cleanups.ForceCleanup(); @@ -1941,7 +2001,7 @@ public: // variable. llvm::Value *value = CGF.Builder.CreateLoad(srcField); - + llvm::Value *null = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType())); @@ -2020,6 +2080,36 @@ public: id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr()); } }; + +/// Emits the copy/dispose helpers for a __block variable that is a non-trivial +/// C struct. +class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers { + QualType VarType; + +public: + NonTrivialCStructByrefHelpers(CharUnits alignment, QualType type) + : BlockByrefHelpers(alignment), VarType(type) {} + + void emitCopy(CodeGenFunction &CGF, Address destField, + Address srcField) override { + CGF.callCStructMoveConstructor(CGF.MakeAddrLValue(destField, VarType), + CGF.MakeAddrLValue(srcField, VarType)); + } + + bool needsDispose() const override { + return VarType.isDestructedType(); + } + + void emitDispose(CodeGenFunction &CGF, Address field) override { + EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin(); + CGF.pushDestroy(VarType.isDestructedType(), field, VarType); + CGF.PopCleanupBlocks(cleanupDepth); + } + + void profileImpl(llvm::FoldingSetNodeID &id) const override { + id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr()); + } +}; } // end anonymous namespace static llvm::Constant * @@ -2059,7 +2149,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo, SC_Static, false, false); - CGF.CGM.SetInternalFunctionAttributes(nullptr, Fn, FI); + CGF.CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); CGF.StartFunction(FD, R, Fn, FI, args); @@ -2083,7 +2173,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo, "src-object"); generator.emitCopy(CGF, destField, srcField); - } + } CGF.FinishFunction(); @@ -2133,7 +2223,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF, SC_Static, false, false); - CGF.CGM.SetInternalFunctionAttributes(nullptr, Fn, FI); + CGF.CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); CGF.StartFunction(FD, R, Fn, FI, args); @@ -2205,6 +2295,13 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr)); } + // If type is a non-trivial C struct type that is non-trivial to + // destructly move or destroy, build the copy and dispose helpers. + if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct || + type.isDestructedType() == QualType::DK_nontrivial_c_struct) + return ::buildByrefHelpers( + CGM, byrefInfo, NonTrivialCStructByrefHelpers(valueAlignment, type)); + // Otherwise, if we don't have a retainable type, there's nothing to do. // that the runtime does extra copies. if (!type->isObjCRetainableType()) return nullptr; @@ -2248,7 +2345,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, BlockFieldFlags flags; if (type->isBlockPointerType()) { flags |= BLOCK_FIELD_IS_BLOCK; - } else if (CGM.getContext().isObjCNSObjectType(type) || + } else if (CGM.getContext().isObjCNSObjectType(type) || type->isObjCObjectPointerType()) { flags |= BLOCK_FIELD_IS_OBJECT; } else { @@ -2307,24 +2404,24 @@ const BlockByrefInfo &CodeGenFunction::getBlockByrefInfo(const VarDecl *D) { llvm::StructType *byrefType = llvm::StructType::create(getLLVMContext(), "struct.__block_byref_" + D->getNameAsString()); - + QualType Ty = D->getType(); CharUnits size; SmallVector<llvm::Type *, 8> types; - + // void *__isa; types.push_back(Int8PtrTy); size += getPointerSize(); - + // void *__forwarding; types.push_back(llvm::PointerType::getUnqual(byrefType)); size += getPointerSize(); - + // int32_t __flags; types.push_back(Int32Ty); size += CharUnits::fromQuantity(4); - + // int32_t __size; types.push_back(Int32Ty); size += CharUnits::fromQuantity(4); @@ -2335,7 +2432,7 @@ const BlockByrefInfo &CodeGenFunction::getBlockByrefInfo(const VarDecl *D) { /// void *__copy_helper; types.push_back(Int8PtrTy); size += getPointerSize(); - + /// void *__destroy_helper; types.push_back(Int8PtrTy); size += getPointerSize(); @@ -2503,30 +2600,10 @@ void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) { EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors? } -namespace { - /// Release a __block variable. - struct CallBlockRelease final : EHScopeStack::Cleanup { - llvm::Value *Addr; - CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {} - - void Emit(CodeGenFunction &CGF, Flags flags) override { - // Should we be passing FIELD_IS_WEAK here? - CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF); - } - }; -} // end anonymous namespace - -/// Enter a cleanup to destroy a __block variable. Note that this -/// cleanup should be a no-op if the variable hasn't left the stack -/// yet; if a cleanup is required for the variable itself, that needs -/// to be done externally. -void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) { - // We don't enter this cleanup if we're in pure-GC mode. - if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) - return; - - EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, - emission.Addr.getPointer()); +void CodeGenFunction::enterByrefCleanup(CleanupKind Kind, Address Addr, + BlockFieldFlags Flags, + bool LoadBlockVarAddr) { + EHStack.pushCleanup<CallBlockRelease>(Kind, Addr, Flags, LoadBlockVarAddr); } /// Adjust the declaration of something from the blocks API. @@ -2559,11 +2636,11 @@ static void configureBlocksRuntimeObject(CodeGenModule &CGM, } } - if (!CGM.getLangOpts().BlocksRuntimeOptional) - return; - - if (GV->isDeclaration() && GV->hasExternalLinkage()) + if (CGM.getLangOpts().BlocksRuntimeOptional && GV->isDeclaration() && + GV->hasExternalLinkage()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); + + CGM.setDSOLocal(GV); } llvm::Constant *CodeGenModule::getBlockObjectDispose() { |
