xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/CGBlocks.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This is the internal state used for llvm translation for block literals.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
140b57cec5SDimitry Andric #define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "CGBuilder.h"
170b57cec5SDimitry Andric #include "CGCall.h"
180b57cec5SDimitry Andric #include "CGValue.h"
190b57cec5SDimitry Andric #include "CodeGenFunction.h"
200b57cec5SDimitry Andric #include "CodeGenTypes.h"
210b57cec5SDimitry Andric #include "clang/AST/CharUnits.h"
220b57cec5SDimitry Andric #include "clang/AST/Expr.h"
230b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
240b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
250b57cec5SDimitry Andric #include "clang/AST/Type.h"
260b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace llvm {
290b57cec5SDimitry Andric class Value;
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric namespace clang {
330b57cec5SDimitry Andric namespace CodeGen {
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric class CGBlockInfo;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric // Flags stored in __block variables.
380b57cec5SDimitry Andric enum BlockByrefFlags {
390b57cec5SDimitry Andric   BLOCK_BYREF_HAS_COPY_DISPOSE         = (1   << 25), // compiler
400b57cec5SDimitry Andric   BLOCK_BYREF_LAYOUT_MASK              = (0xF << 28), // compiler
410b57cec5SDimitry Andric   BLOCK_BYREF_LAYOUT_EXTENDED          = (1   << 28),
420b57cec5SDimitry Andric   BLOCK_BYREF_LAYOUT_NON_OBJECT        = (2   << 28),
430b57cec5SDimitry Andric   BLOCK_BYREF_LAYOUT_STRONG            = (3   << 28),
440b57cec5SDimitry Andric   BLOCK_BYREF_LAYOUT_WEAK              = (4   << 28),
450b57cec5SDimitry Andric   BLOCK_BYREF_LAYOUT_UNRETAINED        = (5   << 28)
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric enum BlockLiteralFlags {
490b57cec5SDimitry Andric   BLOCK_IS_NOESCAPE      =  (1 << 23),
500b57cec5SDimitry Andric   BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
510b57cec5SDimitry Andric   BLOCK_HAS_CXX_OBJ =       (1 << 26),
520b57cec5SDimitry Andric   BLOCK_IS_GLOBAL =         (1 << 28),
530b57cec5SDimitry Andric   BLOCK_USE_STRET =         (1 << 29),
540b57cec5SDimitry Andric   BLOCK_HAS_SIGNATURE  =    (1 << 30),
550b57cec5SDimitry Andric   BLOCK_HAS_EXTENDED_LAYOUT = (1u << 31)
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric class BlockFlags {
580b57cec5SDimitry Andric   uint32_t flags;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric public:
BlockFlags(uint32_t flags)610b57cec5SDimitry Andric   BlockFlags(uint32_t flags) : flags(flags) {}
BlockFlags()620b57cec5SDimitry Andric   BlockFlags() : flags(0) {}
BlockFlags(BlockLiteralFlags flag)630b57cec5SDimitry Andric   BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
BlockFlags(BlockByrefFlags flag)640b57cec5SDimitry Andric   BlockFlags(BlockByrefFlags flag) : flags(flag) {}
650b57cec5SDimitry Andric 
getBitMask()660b57cec5SDimitry Andric   uint32_t getBitMask() const { return flags; }
empty()670b57cec5SDimitry Andric   bool empty() const { return flags == 0; }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   friend BlockFlags operator|(BlockFlags l, BlockFlags r) {
700b57cec5SDimitry Andric     return BlockFlags(l.flags | r.flags);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric   friend BlockFlags &operator|=(BlockFlags &l, BlockFlags r) {
730b57cec5SDimitry Andric     l.flags |= r.flags;
740b57cec5SDimitry Andric     return l;
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric   friend bool operator&(BlockFlags l, BlockFlags r) {
770b57cec5SDimitry Andric     return (l.flags & r.flags);
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric   bool operator==(BlockFlags r) {
800b57cec5SDimitry Andric     return (flags == r.flags);
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric };
830b57cec5SDimitry Andric inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
840b57cec5SDimitry Andric   return BlockFlags(l) | BlockFlags(r);
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric enum BlockFieldFlag_t {
880b57cec5SDimitry Andric   BLOCK_FIELD_IS_OBJECT   = 0x03,  /* id, NSObject, __attribute__((NSObject)),
890b57cec5SDimitry Andric                                     block, ... */
900b57cec5SDimitry Andric   BLOCK_FIELD_IS_BLOCK    = 0x07,  /* a block variable */
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   BLOCK_FIELD_IS_BYREF    = 0x08,  /* the on stack structure holding the __block
930b57cec5SDimitry Andric                                     variable */
940b57cec5SDimitry Andric   BLOCK_FIELD_IS_WEAK     = 0x10,  /* declared __weak, only used in byref copy
950b57cec5SDimitry Andric                                     helpers */
960b57cec5SDimitry Andric   BLOCK_FIELD_IS_ARC      = 0x40,  /* field has ARC-specific semantics */
970b57cec5SDimitry Andric   BLOCK_BYREF_CALLER      = 128,   /* called from __block (byref) copy/dispose
980b57cec5SDimitry Andric                                       support routines */
990b57cec5SDimitry Andric   BLOCK_BYREF_CURRENT_MAX = 256
1000b57cec5SDimitry Andric };
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric class BlockFieldFlags {
1030b57cec5SDimitry Andric   uint32_t flags;
1040b57cec5SDimitry Andric 
BlockFieldFlags(uint32_t flags)1050b57cec5SDimitry Andric   BlockFieldFlags(uint32_t flags) : flags(flags) {}
1060b57cec5SDimitry Andric public:
BlockFieldFlags()1070b57cec5SDimitry Andric   BlockFieldFlags() : flags(0) {}
BlockFieldFlags(BlockFieldFlag_t flag)1080b57cec5SDimitry Andric   BlockFieldFlags(BlockFieldFlag_t flag) : flags(flag) {}
1090b57cec5SDimitry Andric 
getBitMask()1100b57cec5SDimitry Andric   uint32_t getBitMask() const { return flags; }
empty()1110b57cec5SDimitry Andric   bool empty() const { return flags == 0; }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   /// Answers whether the flags indicate that this field is an object
1140b57cec5SDimitry Andric   /// or block pointer that requires _Block_object_assign/dispose.
isSpecialPointer()1150b57cec5SDimitry Andric   bool isSpecialPointer() const { return flags & BLOCK_FIELD_IS_OBJECT; }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   friend BlockFieldFlags operator|(BlockFieldFlags l, BlockFieldFlags r) {
1180b57cec5SDimitry Andric     return BlockFieldFlags(l.flags | r.flags);
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric   friend BlockFieldFlags &operator|=(BlockFieldFlags &l, BlockFieldFlags r) {
1210b57cec5SDimitry Andric     l.flags |= r.flags;
1220b57cec5SDimitry Andric     return l;
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric   friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) {
1250b57cec5SDimitry Andric     return (l.flags & r.flags);
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric   bool operator==(BlockFieldFlags Other) const {
1280b57cec5SDimitry Andric     return flags == Other.flags;
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
1320b57cec5SDimitry Andric   return BlockFieldFlags(l) | BlockFieldFlags(r);
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric /// Information about the layout of a __block variable.
1360b57cec5SDimitry Andric class BlockByrefInfo {
1370b57cec5SDimitry Andric public:
1380b57cec5SDimitry Andric   llvm::StructType *Type;
1390b57cec5SDimitry Andric   unsigned FieldIndex;
1400b57cec5SDimitry Andric   CharUnits ByrefAlignment;
1410b57cec5SDimitry Andric   CharUnits FieldOffset;
1420b57cec5SDimitry Andric };
1430b57cec5SDimitry Andric 
14404eeddc0SDimitry Andric /// Represents a type of copy/destroy operation that should be performed for an
14504eeddc0SDimitry Andric /// entity that's captured by a block.
14604eeddc0SDimitry Andric enum class BlockCaptureEntityKind {
14704eeddc0SDimitry Andric   None,
14804eeddc0SDimitry Andric   CXXRecord, // Copy or destroy
14904eeddc0SDimitry Andric   ARCWeak,
15004eeddc0SDimitry Andric   ARCStrong,
15104eeddc0SDimitry Andric   NonTrivialCStruct,
15204eeddc0SDimitry Andric   BlockObject, // Assign or release
15304eeddc0SDimitry Andric };
15404eeddc0SDimitry Andric 
1550b57cec5SDimitry Andric /// CGBlockInfo - Information to generate a block literal.
1560b57cec5SDimitry Andric class CGBlockInfo {
1570b57cec5SDimitry Andric public:
1580b57cec5SDimitry Andric   /// Name - The name of the block, kindof.
1590b57cec5SDimitry Andric   StringRef Name;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   /// The field index of 'this' within the block, if there is one.
1620b57cec5SDimitry Andric   unsigned CXXThisIndex;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   class Capture {
1650b57cec5SDimitry Andric     uintptr_t Data;
1660b57cec5SDimitry Andric     EHScopeStack::stable_iterator Cleanup;
1670b57cec5SDimitry Andric     CharUnits::QuantityType Offset;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric     /// Type of the capture field. Normally, this is identical to the type of
1700b57cec5SDimitry Andric     /// the capture's VarDecl, but can be different if there is an enclosing
1710b57cec5SDimitry Andric     /// lambda.
1720b57cec5SDimitry Andric     QualType FieldType;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   public:
isIndex()1750b57cec5SDimitry Andric     bool isIndex() const { return (Data & 1) != 0; }
isConstant()1760b57cec5SDimitry Andric     bool isConstant() const { return !isIndex(); }
1770b57cec5SDimitry Andric 
getIndex()1780b57cec5SDimitry Andric     unsigned getIndex() const {
1790b57cec5SDimitry Andric       assert(isIndex());
1800b57cec5SDimitry Andric       return Data >> 1;
1810b57cec5SDimitry Andric     }
getOffset()1820b57cec5SDimitry Andric     CharUnits getOffset() const {
1830b57cec5SDimitry Andric       assert(isIndex());
1840b57cec5SDimitry Andric       return CharUnits::fromQuantity(Offset);
1850b57cec5SDimitry Andric     }
getCleanup()1860b57cec5SDimitry Andric     EHScopeStack::stable_iterator getCleanup() const {
1870b57cec5SDimitry Andric       assert(isIndex());
1880b57cec5SDimitry Andric       return Cleanup;
1890b57cec5SDimitry Andric     }
setCleanup(EHScopeStack::stable_iterator cleanup)1900b57cec5SDimitry Andric     void setCleanup(EHScopeStack::stable_iterator cleanup) {
1910b57cec5SDimitry Andric       assert(isIndex());
1920b57cec5SDimitry Andric       Cleanup = cleanup;
1930b57cec5SDimitry Andric     }
1940b57cec5SDimitry Andric 
getConstant()1950b57cec5SDimitry Andric     llvm::Value *getConstant() const {
1960b57cec5SDimitry Andric       assert(isConstant());
1970b57cec5SDimitry Andric       return reinterpret_cast<llvm::Value*>(Data);
1980b57cec5SDimitry Andric     }
1990b57cec5SDimitry Andric 
fieldType()2000b57cec5SDimitry Andric     QualType fieldType() const {
2010b57cec5SDimitry Andric       return FieldType;
2020b57cec5SDimitry Andric     }
2030b57cec5SDimitry Andric 
20404eeddc0SDimitry Andric     static Capture
makeIndex(unsigned index,CharUnits offset,QualType FieldType,BlockCaptureEntityKind CopyKind,BlockFieldFlags CopyFlags,BlockCaptureEntityKind DisposeKind,BlockFieldFlags DisposeFlags,const BlockDecl::Capture * Cap)20504eeddc0SDimitry Andric     makeIndex(unsigned index, CharUnits offset, QualType FieldType,
20604eeddc0SDimitry Andric               BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags,
20704eeddc0SDimitry Andric               BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags,
20804eeddc0SDimitry Andric               const BlockDecl::Capture *Cap) {
2090b57cec5SDimitry Andric       Capture v;
2100b57cec5SDimitry Andric       v.Data = (index << 1) | 1;
2110b57cec5SDimitry Andric       v.Offset = offset.getQuantity();
2120b57cec5SDimitry Andric       v.FieldType = FieldType;
21304eeddc0SDimitry Andric       v.CopyKind = CopyKind;
21404eeddc0SDimitry Andric       v.CopyFlags = CopyFlags;
21504eeddc0SDimitry Andric       v.DisposeKind = DisposeKind;
21604eeddc0SDimitry Andric       v.DisposeFlags = DisposeFlags;
21704eeddc0SDimitry Andric       v.Cap = Cap;
2180b57cec5SDimitry Andric       return v;
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric 
makeConstant(llvm::Value * value,const BlockDecl::Capture * Cap)22104eeddc0SDimitry Andric     static Capture makeConstant(llvm::Value *value,
22204eeddc0SDimitry Andric                                 const BlockDecl::Capture *Cap) {
2230b57cec5SDimitry Andric       Capture v;
2240b57cec5SDimitry Andric       v.Data = reinterpret_cast<uintptr_t>(value);
22504eeddc0SDimitry Andric       v.Cap = Cap;
2260b57cec5SDimitry Andric       return v;
2270b57cec5SDimitry Andric     }
22804eeddc0SDimitry Andric 
isConstantOrTrivial()22904eeddc0SDimitry Andric     bool isConstantOrTrivial() const {
23004eeddc0SDimitry Andric       return CopyKind == BlockCaptureEntityKind::None &&
23104eeddc0SDimitry Andric              DisposeKind == BlockCaptureEntityKind::None;
23204eeddc0SDimitry Andric     }
23304eeddc0SDimitry Andric 
23404eeddc0SDimitry Andric     BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None,
23504eeddc0SDimitry Andric                            DisposeKind = BlockCaptureEntityKind::None;
23604eeddc0SDimitry Andric     BlockFieldFlags CopyFlags, DisposeFlags;
23704eeddc0SDimitry Andric     const BlockDecl::Capture *Cap;
2380b57cec5SDimitry Andric   };
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   /// CanBeGlobal - True if the block can be global, i.e. it has
2410b57cec5SDimitry Andric   /// no non-constant captures.
2420b57cec5SDimitry Andric   bool CanBeGlobal : 1;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   /// True if the block has captures that would necessitate custom copy or
2450b57cec5SDimitry Andric   /// dispose helper functions if the block were escaping.
2460b57cec5SDimitry Andric   bool NeedsCopyDispose : 1;
2470b57cec5SDimitry Andric 
24804eeddc0SDimitry Andric   /// Indicates whether the block is non-escaping.
24904eeddc0SDimitry Andric   bool NoEscape : 1;
25004eeddc0SDimitry Andric 
2510b57cec5SDimitry Andric   /// HasCXXObject - True if the block's custom copy/dispose functions
2520b57cec5SDimitry Andric   /// need to be run even in GC mode.
2530b57cec5SDimitry Andric   bool HasCXXObject : 1;
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   /// UsesStret : True if the block uses an stret return.  Mutable
2560b57cec5SDimitry Andric   /// because it gets set later in the block-creation process.
2570b57cec5SDimitry Andric   mutable bool UsesStret : 1;
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   /// HasCapturedVariableLayout : True if block has captured variables
2600b57cec5SDimitry Andric   /// and their layout meta-data has been generated.
2610b57cec5SDimitry Andric   bool HasCapturedVariableLayout : 1;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   /// Indicates whether an object of a non-external C++ class is captured. This
2640b57cec5SDimitry Andric   /// bit is used to determine the linkage of the block copy/destroy helper
2650b57cec5SDimitry Andric   /// functions.
2660b57cec5SDimitry Andric   bool CapturesNonExternalType : 1;
2670b57cec5SDimitry Andric 
26804eeddc0SDimitry Andric   /// Mapping from variables to pointers to captures in SortedCaptures.
26904eeddc0SDimitry Andric   llvm::DenseMap<const VarDecl *, Capture *> Captures;
27004eeddc0SDimitry Andric 
27104eeddc0SDimitry Andric   /// The block's captures. Non-constant captures are sorted by their offsets.
27204eeddc0SDimitry Andric   llvm::SmallVector<Capture, 4> SortedCaptures;
2730b57cec5SDimitry Andric 
274*0fca6ea1SDimitry Andric   // Currently we assume that block-pointer types are never signed.
275*0fca6ea1SDimitry Andric   RawAddress LocalAddress;
2760b57cec5SDimitry Andric   llvm::StructType *StructureType;
2770b57cec5SDimitry Andric   const BlockDecl *Block;
2780b57cec5SDimitry Andric   const BlockExpr *BlockExpression;
2790b57cec5SDimitry Andric   CharUnits BlockSize;
2800b57cec5SDimitry Andric   CharUnits BlockAlign;
2810b57cec5SDimitry Andric   CharUnits CXXThisOffset;
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric   // Offset of the gap caused by block header having a smaller
2840b57cec5SDimitry Andric   // alignment than the alignment of the block descriptor. This
2850b57cec5SDimitry Andric   // is the gap offset before the first capturued field.
2860b57cec5SDimitry Andric   CharUnits BlockHeaderForcedGapOffset;
2870b57cec5SDimitry Andric   // Gap size caused by aligning first field after block header.
2880b57cec5SDimitry Andric   // This could be zero if no forced alignment is required.
2890b57cec5SDimitry Andric   CharUnits BlockHeaderForcedGapSize;
2900b57cec5SDimitry Andric 
buildCaptureMap()29104eeddc0SDimitry Andric   void buildCaptureMap() {
29204eeddc0SDimitry Andric     for (auto &C : SortedCaptures)
29304eeddc0SDimitry Andric       Captures[C.Cap->getVariable()] = &C;
29404eeddc0SDimitry Andric   }
29504eeddc0SDimitry Andric 
getCapture(const VarDecl * var)2960b57cec5SDimitry Andric   const Capture &getCapture(const VarDecl *var) const {
2970b57cec5SDimitry Andric     return const_cast<CGBlockInfo*>(this)->getCapture(var);
2980b57cec5SDimitry Andric   }
getCapture(const VarDecl * var)2990b57cec5SDimitry Andric   Capture &getCapture(const VarDecl *var) {
30004eeddc0SDimitry Andric     auto it = Captures.find(var);
3010b57cec5SDimitry Andric     assert(it != Captures.end() && "no entry for variable!");
30204eeddc0SDimitry Andric     return *it->second;
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric 
getBlockDecl()3050b57cec5SDimitry Andric   const BlockDecl *getBlockDecl() const { return Block; }
getBlockExpr()3060b57cec5SDimitry Andric   const BlockExpr *getBlockExpr() const {
3070b57cec5SDimitry Andric     assert(BlockExpression);
3080b57cec5SDimitry Andric     assert(BlockExpression->getBlockDecl() == Block);
3090b57cec5SDimitry Andric     return BlockExpression;
3100b57cec5SDimitry Andric   }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);
3130b57cec5SDimitry Andric };
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric }  // end namespace CodeGen
3160b57cec5SDimitry Andric }  // end namespace clang
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric #endif
319