Initial codegen for block literals.  This is a work in progress.  I've
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
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index d344cc0..8afed89 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -85,7 +85,10 @@
   /// 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 @@
   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 @@
   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
 //===----------------------------------------------------------------------===//