1e5dd7070Spatrick //===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // This is the internal state used for llvm translation for block literals. 10e5dd7070Spatrick // 11e5dd7070Spatrick //===----------------------------------------------------------------------===// 12e5dd7070Spatrick 13e5dd7070Spatrick #ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H 14e5dd7070Spatrick #define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H 15e5dd7070Spatrick 16e5dd7070Spatrick #include "CGBuilder.h" 17e5dd7070Spatrick #include "CGCall.h" 18e5dd7070Spatrick #include "CGValue.h" 19e5dd7070Spatrick #include "CodeGenFunction.h" 20e5dd7070Spatrick #include "CodeGenTypes.h" 21e5dd7070Spatrick #include "clang/AST/CharUnits.h" 22e5dd7070Spatrick #include "clang/AST/Expr.h" 23e5dd7070Spatrick #include "clang/AST/ExprCXX.h" 24e5dd7070Spatrick #include "clang/AST/ExprObjC.h" 25e5dd7070Spatrick #include "clang/AST/Type.h" 26e5dd7070Spatrick #include "clang/Basic/TargetInfo.h" 27e5dd7070Spatrick 28e5dd7070Spatrick namespace llvm { 29e5dd7070Spatrick class Value; 30e5dd7070Spatrick } 31e5dd7070Spatrick 32e5dd7070Spatrick namespace clang { 33e5dd7070Spatrick namespace CodeGen { 34e5dd7070Spatrick 35e5dd7070Spatrick class CGBlockInfo; 36e5dd7070Spatrick 37e5dd7070Spatrick // Flags stored in __block variables. 38e5dd7070Spatrick enum BlockByrefFlags { 39e5dd7070Spatrick BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler 40e5dd7070Spatrick BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler 41e5dd7070Spatrick BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28), 42e5dd7070Spatrick BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28), 43e5dd7070Spatrick BLOCK_BYREF_LAYOUT_STRONG = (3 << 28), 44e5dd7070Spatrick BLOCK_BYREF_LAYOUT_WEAK = (4 << 28), 45e5dd7070Spatrick BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28) 46e5dd7070Spatrick }; 47e5dd7070Spatrick 48e5dd7070Spatrick enum BlockLiteralFlags { 49e5dd7070Spatrick BLOCK_IS_NOESCAPE = (1 << 23), 50e5dd7070Spatrick BLOCK_HAS_COPY_DISPOSE = (1 << 25), 51e5dd7070Spatrick BLOCK_HAS_CXX_OBJ = (1 << 26), 52e5dd7070Spatrick BLOCK_IS_GLOBAL = (1 << 28), 53e5dd7070Spatrick BLOCK_USE_STRET = (1 << 29), 54e5dd7070Spatrick BLOCK_HAS_SIGNATURE = (1 << 30), 55e5dd7070Spatrick BLOCK_HAS_EXTENDED_LAYOUT = (1u << 31) 56e5dd7070Spatrick }; 57e5dd7070Spatrick class BlockFlags { 58e5dd7070Spatrick uint32_t flags; 59e5dd7070Spatrick 60e5dd7070Spatrick public: BlockFlags(uint32_t flags)61e5dd7070Spatrick BlockFlags(uint32_t flags) : flags(flags) {} BlockFlags()62e5dd7070Spatrick BlockFlags() : flags(0) {} BlockFlags(BlockLiteralFlags flag)63e5dd7070Spatrick BlockFlags(BlockLiteralFlags flag) : flags(flag) {} BlockFlags(BlockByrefFlags flag)64e5dd7070Spatrick BlockFlags(BlockByrefFlags flag) : flags(flag) {} 65e5dd7070Spatrick getBitMask()66e5dd7070Spatrick uint32_t getBitMask() const { return flags; } empty()67e5dd7070Spatrick bool empty() const { return flags == 0; } 68e5dd7070Spatrick 69e5dd7070Spatrick friend BlockFlags operator|(BlockFlags l, BlockFlags r) { 70e5dd7070Spatrick return BlockFlags(l.flags | r.flags); 71e5dd7070Spatrick } 72e5dd7070Spatrick friend BlockFlags &operator|=(BlockFlags &l, BlockFlags r) { 73e5dd7070Spatrick l.flags |= r.flags; 74e5dd7070Spatrick return l; 75e5dd7070Spatrick } 76e5dd7070Spatrick friend bool operator&(BlockFlags l, BlockFlags r) { 77e5dd7070Spatrick return (l.flags & r.flags); 78e5dd7070Spatrick } 79e5dd7070Spatrick bool operator==(BlockFlags r) { 80e5dd7070Spatrick return (flags == r.flags); 81e5dd7070Spatrick } 82e5dd7070Spatrick }; 83e5dd7070Spatrick inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) { 84e5dd7070Spatrick return BlockFlags(l) | BlockFlags(r); 85e5dd7070Spatrick } 86e5dd7070Spatrick 87e5dd7070Spatrick enum BlockFieldFlag_t { 88e5dd7070Spatrick BLOCK_FIELD_IS_OBJECT = 0x03, /* id, NSObject, __attribute__((NSObject)), 89e5dd7070Spatrick block, ... */ 90e5dd7070Spatrick BLOCK_FIELD_IS_BLOCK = 0x07, /* a block variable */ 91e5dd7070Spatrick 92e5dd7070Spatrick BLOCK_FIELD_IS_BYREF = 0x08, /* the on stack structure holding the __block 93e5dd7070Spatrick variable */ 94e5dd7070Spatrick BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy 95e5dd7070Spatrick helpers */ 96e5dd7070Spatrick BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */ 97e5dd7070Spatrick BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose 98e5dd7070Spatrick support routines */ 99e5dd7070Spatrick BLOCK_BYREF_CURRENT_MAX = 256 100e5dd7070Spatrick }; 101e5dd7070Spatrick 102e5dd7070Spatrick class BlockFieldFlags { 103e5dd7070Spatrick uint32_t flags; 104e5dd7070Spatrick BlockFieldFlags(uint32_t flags)105e5dd7070Spatrick BlockFieldFlags(uint32_t flags) : flags(flags) {} 106e5dd7070Spatrick public: BlockFieldFlags()107e5dd7070Spatrick BlockFieldFlags() : flags(0) {} BlockFieldFlags(BlockFieldFlag_t flag)108e5dd7070Spatrick BlockFieldFlags(BlockFieldFlag_t flag) : flags(flag) {} 109e5dd7070Spatrick getBitMask()110e5dd7070Spatrick uint32_t getBitMask() const { return flags; } empty()111e5dd7070Spatrick bool empty() const { return flags == 0; } 112e5dd7070Spatrick 113e5dd7070Spatrick /// Answers whether the flags indicate that this field is an object 114e5dd7070Spatrick /// or block pointer that requires _Block_object_assign/dispose. isSpecialPointer()115e5dd7070Spatrick bool isSpecialPointer() const { return flags & BLOCK_FIELD_IS_OBJECT; } 116e5dd7070Spatrick 117e5dd7070Spatrick friend BlockFieldFlags operator|(BlockFieldFlags l, BlockFieldFlags r) { 118e5dd7070Spatrick return BlockFieldFlags(l.flags | r.flags); 119e5dd7070Spatrick } 120e5dd7070Spatrick friend BlockFieldFlags &operator|=(BlockFieldFlags &l, BlockFieldFlags r) { 121e5dd7070Spatrick l.flags |= r.flags; 122e5dd7070Spatrick return l; 123e5dd7070Spatrick } 124e5dd7070Spatrick friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) { 125e5dd7070Spatrick return (l.flags & r.flags); 126e5dd7070Spatrick } 127e5dd7070Spatrick bool operator==(BlockFieldFlags Other) const { 128e5dd7070Spatrick return flags == Other.flags; 129e5dd7070Spatrick } 130e5dd7070Spatrick }; 131e5dd7070Spatrick inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) { 132e5dd7070Spatrick return BlockFieldFlags(l) | BlockFieldFlags(r); 133e5dd7070Spatrick } 134e5dd7070Spatrick 135e5dd7070Spatrick /// Information about the layout of a __block variable. 136e5dd7070Spatrick class BlockByrefInfo { 137e5dd7070Spatrick public: 138e5dd7070Spatrick llvm::StructType *Type; 139e5dd7070Spatrick unsigned FieldIndex; 140e5dd7070Spatrick CharUnits ByrefAlignment; 141e5dd7070Spatrick CharUnits FieldOffset; 142e5dd7070Spatrick }; 143e5dd7070Spatrick 144*12c85518Srobert /// Represents a type of copy/destroy operation that should be performed for an 145*12c85518Srobert /// entity that's captured by a block. 146*12c85518Srobert enum class BlockCaptureEntityKind { 147*12c85518Srobert None, 148*12c85518Srobert CXXRecord, // Copy or destroy 149*12c85518Srobert ARCWeak, 150*12c85518Srobert ARCStrong, 151*12c85518Srobert NonTrivialCStruct, 152*12c85518Srobert BlockObject, // Assign or release 153*12c85518Srobert }; 154*12c85518Srobert 155e5dd7070Spatrick /// CGBlockInfo - Information to generate a block literal. 156e5dd7070Spatrick class CGBlockInfo { 157e5dd7070Spatrick public: 158e5dd7070Spatrick /// Name - The name of the block, kindof. 159e5dd7070Spatrick StringRef Name; 160e5dd7070Spatrick 161e5dd7070Spatrick /// The field index of 'this' within the block, if there is one. 162e5dd7070Spatrick unsigned CXXThisIndex; 163e5dd7070Spatrick 164e5dd7070Spatrick class Capture { 165e5dd7070Spatrick uintptr_t Data; 166e5dd7070Spatrick EHScopeStack::stable_iterator Cleanup; 167e5dd7070Spatrick CharUnits::QuantityType Offset; 168e5dd7070Spatrick 169e5dd7070Spatrick /// Type of the capture field. Normally, this is identical to the type of 170e5dd7070Spatrick /// the capture's VarDecl, but can be different if there is an enclosing 171e5dd7070Spatrick /// lambda. 172e5dd7070Spatrick QualType FieldType; 173e5dd7070Spatrick 174e5dd7070Spatrick public: isIndex()175e5dd7070Spatrick bool isIndex() const { return (Data & 1) != 0; } isConstant()176e5dd7070Spatrick bool isConstant() const { return !isIndex(); } 177e5dd7070Spatrick getIndex()178e5dd7070Spatrick unsigned getIndex() const { 179e5dd7070Spatrick assert(isIndex()); 180e5dd7070Spatrick return Data >> 1; 181e5dd7070Spatrick } getOffset()182e5dd7070Spatrick CharUnits getOffset() const { 183e5dd7070Spatrick assert(isIndex()); 184e5dd7070Spatrick return CharUnits::fromQuantity(Offset); 185e5dd7070Spatrick } getCleanup()186e5dd7070Spatrick EHScopeStack::stable_iterator getCleanup() const { 187e5dd7070Spatrick assert(isIndex()); 188e5dd7070Spatrick return Cleanup; 189e5dd7070Spatrick } setCleanup(EHScopeStack::stable_iterator cleanup)190e5dd7070Spatrick void setCleanup(EHScopeStack::stable_iterator cleanup) { 191e5dd7070Spatrick assert(isIndex()); 192e5dd7070Spatrick Cleanup = cleanup; 193e5dd7070Spatrick } 194e5dd7070Spatrick getConstant()195e5dd7070Spatrick llvm::Value *getConstant() const { 196e5dd7070Spatrick assert(isConstant()); 197e5dd7070Spatrick return reinterpret_cast<llvm::Value*>(Data); 198e5dd7070Spatrick } 199e5dd7070Spatrick fieldType()200e5dd7070Spatrick QualType fieldType() const { 201e5dd7070Spatrick return FieldType; 202e5dd7070Spatrick } 203e5dd7070Spatrick 204*12c85518Srobert static Capture makeIndex(unsigned index,CharUnits offset,QualType FieldType,BlockCaptureEntityKind CopyKind,BlockFieldFlags CopyFlags,BlockCaptureEntityKind DisposeKind,BlockFieldFlags DisposeFlags,const BlockDecl::Capture * Cap)205*12c85518Srobert makeIndex(unsigned index, CharUnits offset, QualType FieldType, 206*12c85518Srobert BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags, 207*12c85518Srobert BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags, 208*12c85518Srobert const BlockDecl::Capture *Cap) { 209e5dd7070Spatrick Capture v; 210e5dd7070Spatrick v.Data = (index << 1) | 1; 211e5dd7070Spatrick v.Offset = offset.getQuantity(); 212e5dd7070Spatrick v.FieldType = FieldType; 213*12c85518Srobert v.CopyKind = CopyKind; 214*12c85518Srobert v.CopyFlags = CopyFlags; 215*12c85518Srobert v.DisposeKind = DisposeKind; 216*12c85518Srobert v.DisposeFlags = DisposeFlags; 217*12c85518Srobert v.Cap = Cap; 218e5dd7070Spatrick return v; 219e5dd7070Spatrick } 220e5dd7070Spatrick makeConstant(llvm::Value * value,const BlockDecl::Capture * Cap)221*12c85518Srobert static Capture makeConstant(llvm::Value *value, 222*12c85518Srobert const BlockDecl::Capture *Cap) { 223e5dd7070Spatrick Capture v; 224e5dd7070Spatrick v.Data = reinterpret_cast<uintptr_t>(value); 225*12c85518Srobert v.Cap = Cap; 226e5dd7070Spatrick return v; 227e5dd7070Spatrick } 228*12c85518Srobert isConstantOrTrivial()229*12c85518Srobert bool isConstantOrTrivial() const { 230*12c85518Srobert return CopyKind == BlockCaptureEntityKind::None && 231*12c85518Srobert DisposeKind == BlockCaptureEntityKind::None; 232*12c85518Srobert } 233*12c85518Srobert 234*12c85518Srobert BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None, 235*12c85518Srobert DisposeKind = BlockCaptureEntityKind::None; 236*12c85518Srobert BlockFieldFlags CopyFlags, DisposeFlags; 237*12c85518Srobert const BlockDecl::Capture *Cap; 238e5dd7070Spatrick }; 239e5dd7070Spatrick 240e5dd7070Spatrick /// CanBeGlobal - True if the block can be global, i.e. it has 241e5dd7070Spatrick /// no non-constant captures. 242e5dd7070Spatrick bool CanBeGlobal : 1; 243e5dd7070Spatrick 244e5dd7070Spatrick /// True if the block has captures that would necessitate custom copy or 245e5dd7070Spatrick /// dispose helper functions if the block were escaping. 246e5dd7070Spatrick bool NeedsCopyDispose : 1; 247e5dd7070Spatrick 248*12c85518Srobert /// Indicates whether the block is non-escaping. 249*12c85518Srobert bool NoEscape : 1; 250*12c85518Srobert 251e5dd7070Spatrick /// HasCXXObject - True if the block's custom copy/dispose functions 252e5dd7070Spatrick /// need to be run even in GC mode. 253e5dd7070Spatrick bool HasCXXObject : 1; 254e5dd7070Spatrick 255e5dd7070Spatrick /// UsesStret : True if the block uses an stret return. Mutable 256e5dd7070Spatrick /// because it gets set later in the block-creation process. 257e5dd7070Spatrick mutable bool UsesStret : 1; 258e5dd7070Spatrick 259e5dd7070Spatrick /// HasCapturedVariableLayout : True if block has captured variables 260e5dd7070Spatrick /// and their layout meta-data has been generated. 261e5dd7070Spatrick bool HasCapturedVariableLayout : 1; 262e5dd7070Spatrick 263e5dd7070Spatrick /// Indicates whether an object of a non-external C++ class is captured. This 264e5dd7070Spatrick /// bit is used to determine the linkage of the block copy/destroy helper 265e5dd7070Spatrick /// functions. 266e5dd7070Spatrick bool CapturesNonExternalType : 1; 267e5dd7070Spatrick 268*12c85518Srobert /// Mapping from variables to pointers to captures in SortedCaptures. 269*12c85518Srobert llvm::DenseMap<const VarDecl *, Capture *> Captures; 270*12c85518Srobert 271*12c85518Srobert /// The block's captures. Non-constant captures are sorted by their offsets. 272*12c85518Srobert llvm::SmallVector<Capture, 4> SortedCaptures; 273e5dd7070Spatrick 274e5dd7070Spatrick Address LocalAddress; 275e5dd7070Spatrick llvm::StructType *StructureType; 276e5dd7070Spatrick const BlockDecl *Block; 277e5dd7070Spatrick const BlockExpr *BlockExpression; 278e5dd7070Spatrick CharUnits BlockSize; 279e5dd7070Spatrick CharUnits BlockAlign; 280e5dd7070Spatrick CharUnits CXXThisOffset; 281e5dd7070Spatrick 282e5dd7070Spatrick // Offset of the gap caused by block header having a smaller 283e5dd7070Spatrick // alignment than the alignment of the block descriptor. This 284e5dd7070Spatrick // is the gap offset before the first capturued field. 285e5dd7070Spatrick CharUnits BlockHeaderForcedGapOffset; 286e5dd7070Spatrick // Gap size caused by aligning first field after block header. 287e5dd7070Spatrick // This could be zero if no forced alignment is required. 288e5dd7070Spatrick CharUnits BlockHeaderForcedGapSize; 289e5dd7070Spatrick 290e5dd7070Spatrick /// The next block in the block-info chain. Invalid if this block 291e5dd7070Spatrick /// info is not part of the CGF's block-info chain, which is true 292e5dd7070Spatrick /// if it corresponds to a global block or a block whose expression 293e5dd7070Spatrick /// has been encountered. 294e5dd7070Spatrick CGBlockInfo *NextBlockInfo; 295e5dd7070Spatrick buildCaptureMap()296*12c85518Srobert void buildCaptureMap() { 297*12c85518Srobert for (auto &C : SortedCaptures) 298*12c85518Srobert Captures[C.Cap->getVariable()] = &C; 299*12c85518Srobert } 300*12c85518Srobert getCapture(const VarDecl * var)301e5dd7070Spatrick const Capture &getCapture(const VarDecl *var) const { 302e5dd7070Spatrick return const_cast<CGBlockInfo*>(this)->getCapture(var); 303e5dd7070Spatrick } getCapture(const VarDecl * var)304e5dd7070Spatrick Capture &getCapture(const VarDecl *var) { 305*12c85518Srobert auto it = Captures.find(var); 306e5dd7070Spatrick assert(it != Captures.end() && "no entry for variable!"); 307*12c85518Srobert return *it->second; 308e5dd7070Spatrick } 309e5dd7070Spatrick getBlockDecl()310e5dd7070Spatrick const BlockDecl *getBlockDecl() const { return Block; } getBlockExpr()311e5dd7070Spatrick const BlockExpr *getBlockExpr() const { 312e5dd7070Spatrick assert(BlockExpression); 313e5dd7070Spatrick assert(BlockExpression->getBlockDecl() == Block); 314e5dd7070Spatrick return BlockExpression; 315e5dd7070Spatrick } 316e5dd7070Spatrick 317e5dd7070Spatrick CGBlockInfo(const BlockDecl *blockDecl, StringRef Name); 318e5dd7070Spatrick }; 319e5dd7070Spatrick 320e5dd7070Spatrick } // end namespace CodeGen 321e5dd7070Spatrick } // end namespace clang 322e5dd7070Spatrick 323e5dd7070Spatrick #endif 324