]> granicus.if.org Git - clang/commitdiff
Add a very basic implemenation of global blocks. This needs to be cleaned up.
authorAnders Carlsson <andersca@mac.com>
Thu, 12 Feb 2009 17:55:02 +0000 (17:55 +0000)
committerAnders Carlsson <andersca@mac.com>
Thu, 12 Feb 2009 17:55:02 +0000 (17:55 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64387 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/CodeGen/CGBlocks.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h

index 408c660a48912670b7fa49b7bea4404c4cd80c32..05d088b75938363ed1e4855da4f3bd90a70f07d3 100644 (file)
@@ -2098,6 +2098,7 @@ public:
   BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty), 
             TheBlock(BD) {}
 
+  const BlockDecl *getBlockDecl() const { return TheBlock; }
   BlockDecl *getBlockDecl() { return TheBlock; }
   
   // Convenience functions for probing the underlying BlockDecl.
index 38aab2d3acb4f6fdd796c0e968d9d239b144cf24..9aa5207a443849a41632f2c4de7fe0c38da24022 100644 (file)
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "llvm/Module.h"
+#include "llvm/Target/TargetData.h"
 
 #include <algorithm>
 
 using namespace clang;
 using namespace CodeGen;
 
-static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) {
+// Block flags
+enum {
+  IsGlobal = 1 << 28
+};
+
+static const llvm::Type *getBlockDescriptorType(CodeGenModule &CGM) {
   static const llvm::Type *Ty = 0;
     
   if (!Ty) {
     const llvm::Type *UnsignedLongTy = 
-      CGF.ConvertType(CGF.getContext().UnsignedLongTy);
+      CGM.getTypes().ConvertType(CGM.getContext().UnsignedLongTy);
         
     // struct __block_descriptor {
     //   unsigned long reserved;
@@ -35,13 +41,13 @@ static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) {
                                UnsignedLongTy, 
                                NULL);
         
-    CGF.CGM.getModule().addTypeName("struct.__block_descriptor", Ty);
+    CGM.getModule().addTypeName("struct.__block_descriptor", Ty);
   }
     
   return Ty;
 }
 
-static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
+static const llvm::Type *getGenericBlockLiteralType(CodeGenModule &CGM) {
   static const llvm::Type *Ty = 0;
     
   if (!Ty) {
@@ -49,7 +55,7 @@ static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
       llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
         
     const llvm::Type *BlockDescPtrTy = 
-      llvm::PointerType::getUnqual(getBlockDescriptorType(CGF));
+      llvm::PointerType::getUnqual(getBlockDescriptorType(CGM));
         
     // struct __block_literal_generic {
     //   void *isa;
@@ -65,7 +71,7 @@ static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
                                BlockDescPtrTy,
                                NULL);
         
-    CGF.CGM.getModule().addTypeName("struct.__block_literal_generic", Ty);
+    CGM.getModule().addTypeName("struct.__block_literal_generic", Ty);
   }
   
   return Ty;
@@ -74,8 +80,7 @@ static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
 /// getBlockFunctionType - Given a BlockPointerType, will return the 
 /// function type for the block, including the first block literal argument.
 static QualType getBlockFunctionType(ASTContext &Ctx,
-                                     const BlockPointerType *BPT)
-{
+                                     const BlockPointerType *BPT) {
   const FunctionTypeProto *FTy = cast<FunctionTypeProto>(BPT->getPointeeType());
   
   llvm::SmallVector<QualType, 8> Types;
@@ -90,8 +95,7 @@ static QualType getBlockFunctionType(ASTContext &Ctx,
                              FTy->isVariadic(), 0);
 }
 
-RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E)
-{
+RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
   const BlockPointerType *BPT = 
     E->getCallee()->getType()->getAsBlockPointerType();
   
@@ -99,7 +103,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E)
 
   // Get a pointer to the generic block literal.
   const llvm::Type *BlockLiteralTy =
-    llvm::PointerType::getUnqual(getGenericBlockLiteralType(*this));
+    llvm::PointerType::getUnqual(getGenericBlockLiteralType(CGM));
 
   // Bitcast the callee to a block literal.
   llvm::Value *BlockLiteral = 
@@ -135,3 +139,117 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E)
   return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args), 
                   Func, Args);
 }
+
+llvm::Constant *CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE) {
+  if (!NSConcreteGlobalBlock) {
+    const llvm::Type *Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+    // FIXME: Wee should have a CodeGenModule::AddRuntimeVariable that does the 
+    // same thing as CreateRuntimeFunction if there's already a variable with
+    // the same name.
+    NSConcreteGlobalBlock = 
+      new llvm::GlobalVariable(Ty, false,
+                              llvm::GlobalVariable::ExternalLinkage, 0, 
+                              "_NSConcreteGlobalBlock", &getModule());      
+  }
+
+  // Generate the block descriptor.
+  const llvm::Type *UnsignedLongTy = Types.ConvertType(Context.UnsignedLongTy);
+  
+  llvm::Constant *DescriptorFields[2];
+  
+  // Reserved
+  DescriptorFields[0] = llvm::Constant::getNullValue(UnsignedLongTy);
+  
+  // Block literal size. For global blocks we just use the size of the generic
+  // block literal struct.
+  uint64_t BlockLiteralSize = 
+    TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType(*this)) / 8;
+  DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
+  
+  llvm::Constant *DescriptorStruct = 
+    llvm::ConstantStruct::get(&DescriptorFields[0], 2);
+  
+  llvm::GlobalVariable *Descriptor =
+    new llvm::GlobalVariable(DescriptorStruct->getType(), true,
+                             llvm::GlobalVariable::InternalLinkage, 
+                             DescriptorStruct, "__block_descriptor_global", 
+                             &getModule());
+  
+  // Generate the constants for the block literal.
+  llvm::Constant *LiteralFields[5];
+  
+  CodeGenFunction::BlockInfo Info(0, "global");
+  llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info);
+  
+  // isa
+  LiteralFields[0] = NSConcreteGlobalBlock;
+  
+  // Flags
+  LiteralFields[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, IsGlobal);
+  
+  // Reserved
+  LiteralFields[2] = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+  
+  // Function
+  LiteralFields[3] = Fn;
+  
+  // Descriptor
+  LiteralFields[4] = Descriptor;
+  
+  llvm::Constant *BlockLiteralStruct = 
+    llvm::ConstantStruct::get(&LiteralFields[0], 5);
+  
+  llvm::GlobalVariable *BlockLiteral = 
+    new llvm::GlobalVariable(BlockLiteralStruct->getType(), true,
+                             llvm::GlobalVariable::InternalLinkage, 
+                             BlockLiteralStruct, "__block_literal_global", 
+                             &getModule());
+  
+  return BlockLiteral;
+}
+
+llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr,
+                                                       const BlockInfo& Info)
+{
+  const FunctionTypeProto *FTy = 
+    cast<FunctionTypeProto>(Expr->getFunctionType());
+  
+  FunctionArgList Args;
+  
+  const BlockDecl *BD = Expr->getBlockDecl();
+
+  // FIXME: This leaks
+  ImplicitParamDecl *SelfDecl = 
+    ImplicitParamDecl::Create(getContext(), 0,
+                              SourceLocation(), 0,
+                              getContext().getPointerType(getContext().VoidTy));
+  
+  Args.push_back(std::make_pair(SelfDecl, SelfDecl->getType()));
+  
+  for (BlockDecl::param_iterator i = BD->param_begin(), 
+       e = BD->param_end(); i != e; ++i)
+    Args.push_back(std::make_pair(*e, (*e)->getType()));
+  
+  const CGFunctionInfo &FI = 
+    CGM.getTypes().getFunctionInfo(FTy->getResultType(), Args);
+
+  std::string Name = std::string("__block_function_") + Info.NameSuffix;
+
+  CodeGenTypes &Types = CGM.getTypes();
+  const llvm::FunctionType *LTy = Types.GetFunctionType(FI, FTy->isVariadic());
+  
+  llvm::Function *Fn = 
+    llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+                           Name,
+                           &CGM.getModule());
+  
+  StartFunction(BD, FTy->getResultType(), Fn, Args, 
+                Expr->getBody()->getLocEnd());
+  EmitStmt(Expr->getBody());
+  FinishFunction(cast<CompoundStmt>(Expr->getBody())->getRBracLoc());
+
+  return Fn;
+}
+
+
index 1f6da8a4142f3922788f20da3d2700f0c199fe27..91153f796b3e6f33cd2d0ff63aa9f8dc413af660 100644 (file)
@@ -371,6 +371,10 @@ public:
     return Visit(E->getSubExpr());
   }
     
+  llvm::Constant *VisitBlockExpr(const BlockExpr *E) {
+    return CGM.GetAddrOfGlobalBlock(E);
+  }
+  
   // Utility methods
   const llvm::Type *ConvertType(QualType T) {
     return CGM.getTypes().ConvertType(T);
index f6196fe64f23f788041e31e17228fd59f1a4fa4b..ce4a424c33818e11528471db4881fb2c8c1d9db1 100644 (file)
@@ -243,6 +243,18 @@ public:
   void GenerateObjCSetter(ObjCImplementationDecl *IMP,
                           const ObjCPropertyImplDecl *PID);
 
+  struct BlockInfo {
+    const llvm::Type *BlockLiteralTy;
+    
+    const char *NameSuffix;
+
+    BlockInfo(const llvm::Type *blt, const char *ns) 
+      :  BlockLiteralTy(blt), NameSuffix(ns) {}
+  };
+  
+  llvm::Function *GenerateBlockFunction(const BlockExpr *Expr,
+                                        const BlockInfo& Info);
+  
   void GenerateCode(const FunctionDecl *FD,
                     llvm::Function *Fn);
   void StartFunction(const Decl *D, QualType RetTy,
index 7192e9db2f257a2646848650c031273c9314bd05..a3b79562d140ec890ef64ccf9ad5ee037e77dffd 100644 (file)
@@ -35,7 +35,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO,
                              Diagnostic &diags, bool GenerateDebugInfo)
   : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags),
     Types(C, M, TD), Runtime(0), MemCpyFn(0), MemMoveFn(0), MemSetFn(0),
-    CFConstantStringClassRef(0) {
+    CFConstantStringClassRef(0), NSConcreteGlobalBlock(0) {
 
   if (Features.ObjC1) {
     if (Features.NeXTRuntime) {
@@ -1125,4 +1125,3 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
     assert(isa<TypeDecl>(D) && "Unsupported decl kind");
   }
 }
-  
index bedefcaa3f9977fefaa68d470e8d12c5dd76a6bb..0c3964fd5f9157fe8ab113ea324a0762c6cfbac4 100644 (file)
@@ -40,6 +40,7 @@ namespace clang {
   class ObjCImplementationDecl;
   class ObjCCategoryImplDecl;
   class ObjCProtocolDecl;
+  class BlockExpr;
   class Decl;
   class Expr;
   class Stmt;
@@ -121,6 +122,10 @@ class CodeGenModule {
   /// Obj-C class pointer.
   llvm::Constant *CFConstantStringClassRef;
   
+  /// NSConcreteGlobalBlock - Cached reference to the clas pointer for 
+  /// global blocks.
+  llvm::Constant *NSConcreteGlobalBlock;
+  
   std::vector<llvm::Function *> BuiltinFunctions;
 public:
   CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M, 
@@ -196,6 +201,8 @@ public:
   llvm::Constant *GetAddrOfConstantCString(const std::string &str,
                                            const char *GlobalName=0);
   
+  llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE);
+  
   /// getBuiltinLibFunction - Given a builtin id for a function like
   /// "__builtin_fabsf", return a Function* for "fabsf".
   llvm::Function *getBuiltinLibFunction(unsigned BuiltinID);