1 //===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This is the internal state used for llvm translation for block literals.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef CLANG_CODEGEN_CGBLOCKS_H
15 #define CLANG_CODEGEN_CGBLOCKS_H
16 
17 #include "CodeGenTypes.h"
18 #include "clang/AST/Type.h"
19 #include "llvm/Module.h"
20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "clang/Basic/TargetInfo.h"
23 #include "clang/AST/Expr.h"
24 #include "clang/AST/ExprCXX.h"
25 #include "clang/AST/ExprObjC.h"
26 
27 #include <vector>
28 #include <map>
29 
30 #include "CGBuilder.h"
31 #include "CGCall.h"
32 #include "CGValue.h"
33 
34 namespace llvm {
35   class Module;
36   class Constant;
37   class Function;
38   class GlobalValue;
39   class TargetData;
40   class FunctionType;
41   class Value;
42   class LLVMContext;
43 }
44 
45 namespace clang {
46 
47 namespace CodeGen {
48 class CodeGenModule;
49 
50 class BlockBase {
51 public:
52     enum {
53         BLOCK_NEEDS_FREE =        (1 << 24),
54         BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
55         BLOCK_HAS_CXX_OBJ =       (1 << 26),
56         BLOCK_IS_GC =             (1 << 27),
57         BLOCK_IS_GLOBAL =         (1 << 28),
58         BLOCK_HAS_DESCRIPTOR =    (1 << 29)
59     };
60 };
61 
62 class BlockModule : public BlockBase {
63   ASTContext &Context;
64   llvm::Module &TheModule;
65   const llvm::TargetData &TheTargetData;
66   CodeGenTypes &Types;
67   CodeGenModule &CGM;
68   llvm::LLVMContext &VMContext;
69 
70   ASTContext &getContext() const { return Context; }
71   llvm::Module &getModule() const { return TheModule; }
72   CodeGenTypes &getTypes() { return Types; }
73   const llvm::TargetData &getTargetData() const { return TheTargetData; }
74 public:
75   llvm::Constant *getNSConcreteGlobalBlock();
76   llvm::Constant *getNSConcreteStackBlock();
77   int getGlobalUniqueCount() { return ++Block.GlobalUniqueCount; }
78   const llvm::Type *getBlockDescriptorType();
79 
80   const llvm::Type *getGenericBlockLiteralType();
81   const llvm::Type *getGenericExtendedBlockLiteralType();
82 
83   llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *);
84 
85   /// NSConcreteGlobalBlock - Cached reference to the class pointer for global
86   /// blocks.
87   llvm::Constant *NSConcreteGlobalBlock;
88 
89   /// NSConcreteStackBlock - Cached reference to the class poinnter for stack
90   /// blocks.
91   llvm::Constant *NSConcreteStackBlock;
92 
93   const llvm::Type *BlockDescriptorType;
94   const llvm::Type *GenericBlockLiteralType;
95   const llvm::Type *GenericExtendedBlockLiteralType;
96   struct {
97     int GlobalUniqueCount;
98   } Block;
99 
100   llvm::Value *BlockObjectAssign;
101   llvm::Value *BlockObjectDispose;
102   const llvm::Type *PtrToInt8Ty;
103 
104   std::map<uint64_t, llvm::Constant *> AssignCache;
105   std::map<uint64_t, llvm::Constant *> DestroyCache;
106 
107   BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD,
108               CodeGenTypes &T, CodeGenModule &CodeGen)
109     : Context(C), TheModule(M), TheTargetData(TD), Types(T),
110       CGM(CodeGen), VMContext(M.getContext()),
111       NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0),
112       GenericBlockLiteralType(0), GenericExtendedBlockLiteralType(0),
113       BlockObjectAssign(0), BlockObjectDispose(0) {
114     Block.GlobalUniqueCount = 0;
115     PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
116   }
117 };
118 
119 class BlockFunction : public BlockBase {
120   CodeGenModule &CGM;
121   CodeGenFunction &CGF;
122   ASTContext &getContext() const;
123 
124 protected:
125   llvm::LLVMContext &VMContext;
126 
127 public:
128   const llvm::Type *PtrToInt8Ty;
129   struct HelperInfo {
130     int index;
131     int flag;
132     bool RequiresCopying;
133   };
134 
135   enum {
136     BLOCK_FIELD_IS_OBJECT   =  3,  /* id, NSObject, __attribute__((NSObject)),
137                                       block, ... */
138     BLOCK_FIELD_IS_BLOCK    =  7,  /* a block variable */
139     BLOCK_FIELD_IS_BYREF    =  8,  /* the on stack structure holding the __block
140                                       variable */
141     BLOCK_FIELD_IS_WEAK     = 16,  /* declared __weak, only used in byref copy
142                                       helpers */
143     BLOCK_BYREF_CALLER      = 128,  /* called from __block (byref) copy/dispose
144                                       support routines */
145     BLOCK_BYREF_CURRENT_MAX = 256
146   };
147 
148   /// BlockInfo - Information to generate a block literal.
149   struct BlockInfo {
150     /// BlockLiteralTy - The type of the block literal.
151     const llvm::Type *BlockLiteralTy;
152 
153     /// Name - the name of the function this block was created for, if any.
154     const char *Name;
155 
156     /// ByCopyDeclRefs - Variables from parent scopes that have been imported
157     /// into this block.
158     llvm::SmallVector<const BlockDeclRefExpr *, 8> ByCopyDeclRefs;
159 
160     // ByRefDeclRefs - __block variables from parent scopes that have been
161     // imported into this block.
162     llvm::SmallVector<const BlockDeclRefExpr *, 8> ByRefDeclRefs;
163 
164     BlockInfo(const llvm::Type *blt, const char *n)
165       : BlockLiteralTy(blt), Name(n) {
166       // Skip asm prefix, if any.
167       if (Name && Name[0] == '\01')
168         ++Name;
169     }
170   };
171 
172   CGBuilderTy &Builder;
173 
174   BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B);
175 
176   /// BlockOffset - The offset in bytes for the next allocation of an
177   /// imported block variable.
178   uint64_t BlockOffset;
179   /// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
180   uint64_t BlockAlign;
181 
182   /// getBlockOffset - Allocate an offset for the ValueDecl from a
183   /// BlockDeclRefExpr in a block literal (BlockExpr).
184   uint64_t getBlockOffset(const BlockDeclRefExpr *E);
185 
186   /// BlockHasCopyDispose - True iff the block uses copy/dispose.
187   bool BlockHasCopyDispose;
188 
189   /// BlockDeclRefDecls - Decls from BlockDeclRefExprs in apperance order
190   /// in a block literal.  Decls without names are used for padding.
191   llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls;
192 
193   /// BlockDecls - Offsets for all Decls in BlockDeclRefExprs.
194   std::map<const Decl*, uint64_t> BlockDecls;
195 
196   ImplicitParamDecl *BlockStructDecl;
197   ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
198 
199   llvm::Constant *GenerateCopyHelperFunction(bool, const llvm::StructType *,
200                                              std::vector<HelperInfo> *);
201   llvm::Constant *GenerateDestroyHelperFunction(bool, const llvm::StructType *,
202                                                 std::vector<HelperInfo> *);
203 
204   llvm::Constant *BuildCopyHelper(const llvm::StructType *,
205                                   std::vector<HelperInfo> *);
206   llvm::Constant *BuildDestroyHelper(const llvm::StructType *,
207                                      std::vector<HelperInfo> *);
208 
209   llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *, int flag);
210   llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T, int);
211 
212   llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, int flag,
213                                        unsigned Align);
214   llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag,
215                                           unsigned Align);
216 
217   llvm::Value *getBlockObjectAssign();
218   llvm::Value *getBlockObjectDispose();
219   void BuildBlockRelease(llvm::Value *DeclPtr, int flag = BLOCK_FIELD_IS_BYREF);
220 
221   bool BlockRequiresCopying(QualType Ty) {
222     if (Ty->isBlockPointerType())
223       return true;
224     if (getContext().isObjCNSObjectType(Ty))
225       return true;
226     if (Ty->isObjCObjectPointerType())
227       return true;
228     return false;
229   }
230 };
231 
232 }  // end namespace CodeGen
233 }  // end namespace clang
234 
235 #endif
236