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