xref: /openbsd-src/gnu/llvm/clang/lib/CodeGen/CGBlocks.h (revision 12c855180aad702bbcca06e0398d774beeafb155)
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