]> granicus.if.org Git - clang/commitdiff
Initial codegen for block literals. This is a work in progress. I've
authorMike Stump <mrs@apple.com>
Thu, 12 Feb 2009 18:29:15 +0000 (18:29 +0000)
committerMike Stump <mrs@apple.com>
Thu, 12 Feb 2009 18:29:15 +0000 (18:29 +0000)
tried to put FIXMEs on the most important things to fix up.  Lots left
to do including more codegen, more documentation and cleaning code and
style cleanups.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64390 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprScalar.cpp

index d344cc0d1bdb5759a973920d53ab1908b855ae24..8afed8997b873e3e2865fcd52da70f61cb028f69 100644 (file)
@@ -85,7 +85,10 @@ public:
   /// type is an LLVM scalar type.
   Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
                                        QualType SrcTy, QualType DstTy);
-    
+
+  llvm::Constant *BuildBlockLiteralTmp ();
+  llvm::Constant *BuildDescriptorBlockDecl();
+
   //===--------------------------------------------------------------------===//
   //                            Visitor Methods
   //===--------------------------------------------------------------------===//
@@ -319,11 +322,7 @@ public:
   Value *VisitBinComma      (const BinaryOperator *E);
 
   // Other Operators.
-  Value *VisitBlockExpr(const BlockExpr *BE) {
-    CGF.ErrorUnsupported(BE, "block expression");
-    return llvm::UndefValue::get(CGF.ConvertType(BE->getType()));
-  }
-
+  Value *VisitBlockExpr(const BlockExpr *BE);
   Value *VisitConditionalOperator(const ConditionalOperator *CO);
   Value *VisitChooseExpr(ChooseExpr *CE);
   Value *VisitOverloadExpr(OverloadExpr *OE);
@@ -1361,6 +1360,143 @@ Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
   return C;
 }
 
+enum {
+  BLOCK_NEEDS_FREE =        (1 << 24),
+  BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
+  BLOCK_HAS_CXX_OBJ =       (1 << 26),
+  BLOCK_IS_GC =             (1 << 27),
+  BLOCK_IS_GLOBAL =         (1 << 28),
+  BLOCK_HAS_DESCRIPTOR =    (1 << 29)
+};
+
+llvm::Constant *ScalarExprEmitter::BuildDescriptorBlockDecl() {
+  // FIXME: Push up.
+  bool BlockHasCopyDispose = false;
+
+  const llvm::PointerType *PtrToInt8Ty
+    = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+  llvm::Constant *C;
+  std::vector<llvm::Constant*> Elts;
+
+  // reserved
+  const llvm::IntegerType *LongTy
+    = cast<llvm::IntegerType>(
+        CGF.CGM.getTypes().ConvertType(CGF.CGM.getContext().LongTy));
+  C = llvm::ConstantInt::get(LongTy, 0);
+  Elts.push_back(C);
+
+  // Size
+  // FIXME: This should be the size of BlockStructType
+  C = llvm::ConstantInt::get(LongTy, 20);
+  Elts.push_back(C);
+
+  if (BlockHasCopyDispose) {
+    // copy_func_helper_decl
+    C = llvm::ConstantInt::get(LongTy, 0);
+    C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
+    Elts.push_back(C);
+
+    // destroy_func_decl
+    C = llvm::ConstantInt::get(LongTy, 0);
+    C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
+    Elts.push_back(C);
+  }
+
+  C = llvm::ConstantStruct::get(Elts);
+
+  // FIXME: Should be in module?
+  static int desc_unique_count;
+  char Name[32];
+  sprintf(Name, "__block_descriptor_tmp_%d", ++desc_unique_count);
+  C = new llvm::GlobalVariable(C->getType(), true,
+                               llvm::GlobalValue::InternalLinkage,
+                               C, Name, &CGF.CGM.getModule());
+  return C;
+}
+
+llvm::Constant *ScalarExprEmitter::BuildBlockLiteralTmp() {
+  // FIXME: Push up
+  bool BlockHasCopyDispose = false;
+  bool insideFunction = false;
+  bool BlockRefDeclList = false;
+  bool BlockByrefDeclList = false;
+
+  std::vector<llvm::Constant*> Elts;
+  llvm::Constant *C;
+
+  bool staticBlockTmp = (BlockRefDeclList == 0
+                         && BlockByrefDeclList == 0);
+
+  {
+    // C = BuildBlockStructInitlist();
+    unsigned int flags = BLOCK_HAS_DESCRIPTOR;
+
+    if (BlockHasCopyDispose)
+      flags |= BLOCK_HAS_COPY_DISPOSE;
+
+    const llvm::PointerType *PtrToInt8Ty
+      = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+    // FIXME: static?  What if we start up a new, unrelated module?
+    // logically we want 1 per module.
+    static llvm::Constant *NSConcreteGlobalBlock_decl
+      = new llvm::GlobalVariable(PtrToInt8Ty, false, 
+                                 llvm::GlobalValue::ExternalLinkage,
+                                 0, "_NSConcreteGlobalBlock",
+                                 &CGF.CGM.getModule());
+    static llvm::Constant *NSConcreteStackBlock_decl
+      = new llvm::GlobalVariable(PtrToInt8Ty, false, 
+                                 llvm::GlobalValue::ExternalLinkage,
+                                 0, "_NSConcreteStackBlock",
+                                 &CGF.CGM.getModule());
+    C = NSConcreteStackBlock_decl;
+    if (!insideFunction ||
+        (!BlockRefDeclList && !BlockByrefDeclList)) {
+      C = NSConcreteGlobalBlock_decl;
+      flags |= BLOCK_IS_GLOBAL;
+    }
+    C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
+    Elts.push_back(C);
+
+    // __flags
+    const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
+      CGF.CGM.getTypes().ConvertType(CGF.CGM.getContext().IntTy));
+    C = llvm::ConstantInt::get(IntTy, flags);
+    Elts.push_back(C);
+
+    // __reserved
+    C = llvm::ConstantInt::get(IntTy, 0);
+    Elts.push_back(C);
+
+    // __FuncPtr
+    // FIXME: Build this up.
+    Elts.push_back(C);
+
+    // __descriptor
+    Elts.push_back(BuildDescriptorBlockDecl());
+
+    // FIXME: Add block_original_ref_decl_list and block_byref_decl_list.
+  }
+  
+  C = llvm::ConstantStruct::get(Elts);
+
+  char Name[32];
+  // FIXME: Boost in CGM?
+  static int global_unique_count;
+  sprintf(Name, "__block_holder_tmp_%d", ++global_unique_count);
+  C = new llvm::GlobalVariable(C->getType(), true,
+                               llvm::GlobalValue::InternalLinkage,
+                               C, Name, &CGF.CGM.getModule());
+  return C;
+}
+
+Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) {
+  llvm::Constant *C = BuildBlockLiteralTmp();
+
+  const llvm::PointerType *PtrToInt8Ty
+    = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+  return llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
+}
+
 //===----------------------------------------------------------------------===//
 //                         Entry Point into this File
 //===----------------------------------------------------------------------===//