[cfe-commits] r66007 - in /cfe/trunk/lib/CodeGen: CGBlocks.cpp CGDecl.cpp CGExpr.cpp CodeGenFunction.h CodeGenModule.h

Mike Stump mrs at apple.com
Tue Mar 3 19:23:47 PST 2009


Author: mrs
Date: Tue Mar  3 21:23:46 2009
New Revision: 66007

URL: http://llvm.org/viewvc/llvm-project?rev=66007&view=rev
Log:
Improved ABI compliance for __block variables.  No testcases yet as we
still give an unsupported error for them due to the fact this is a
work in progress.

Modified:
    cfe/trunk/lib/CodeGen/CGBlocks.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.h

Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=66007&r1=66006&r2=66007&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Tue Mar  3 21:23:46 2009
@@ -21,15 +21,6 @@
 using namespace clang;
 using namespace CodeGen;
 
-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 *CodeGenFunction::BuildDescriptorBlockDecl(uint64_t Size) {
   const llvm::PointerType *PtrToInt8Ty
     = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
@@ -142,7 +133,11 @@
   CollectBlockDeclRefInfo(BE->getBody(), Info);
 
   // Check if the block can be global.
-  if (CanBlockBeGlobal(Info))
+  // FIXME: This test doesn't work for nested blocks yet.  Longer
+  // term, I'd like to just have one code path.  We should move
+  // this function into CGM and pass CGF, then we can just check to
+  // see if CGF is 0.
+  if (0 && CanBlockBeGlobal(Info))
     return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
     
   std::vector<llvm::Constant*> Elts;
@@ -209,9 +204,11 @@
       const Expr *E = subBlockDeclRefDecls[i];
       const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
       QualType Ty = E->getType();
-      if (BDRE && BDRE->isByRef())
-        Ty = getContext().getPointerType(Ty);
-      Types[i+5] = ConvertType(Ty);
+      if (BDRE && BDRE->isByRef()) {
+        uint64_t Align = getContext().getDeclAlignInBytes(BDRE->getDecl());
+        Types[i+5] = llvm::PointerType::get(BuildByRefType(Ty, Align), 0);
+      } else
+        Types[i+5] = ConvertType(Ty);
     }
 
     llvm::Type *Ty = llvm::StructType::get(Types, true);
@@ -237,23 +234,41 @@
         BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
         VD = BDRE->getDecl();
 
+        llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
         // FIXME: I want a better way to do this.
         if (LocalDeclMap[VD]) {
-          E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
-                                              VD->getType(), SourceLocation(),
-                                              false, false);
+          if (BDRE->isByRef()) {
+            const llvm::Type *Ty = Types[i+5];
+            llvm::Value *Loc = LocalDeclMap[VD];
+            Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
+            Loc = Builder.CreateLoad(Loc, false);
+            Loc = Builder.CreateBitCast(Loc, Ty);
+            Builder.CreateStore(Loc, Addr);
+            continue;
+          } else
+            E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
+                                                VD->getType(), SourceLocation(),
+                                                false, false);
         }
-        if (BDRE->isByRef())
+        if (BDRE->isByRef()) {
+          // FIXME: __block in nested literals
           E = new (getContext())
             UnaryOperator(E, UnaryOperator::AddrOf,
                           getContext().getPointerType(E->getType()),
                           SourceLocation());
+        }
 
-        llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
         RValue r = EmitAnyExpr(E, Addr, false);
-        if (r.isScalar())
-          Builder.CreateStore(r.getScalarVal(), Addr);
-        else if (r.isComplex())
+        if (r.isScalar()) {
+          llvm::Value *Loc = r.getScalarVal();
+          const llvm::Type *Ty = Types[i+5];
+          if  (BDRE->isByRef()) {
+            Loc = Builder.CreateBitCast(Loc, Ty);
+            Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
+            Loc = Builder.CreateBitCast(Loc, Ty);
+          }
+          Builder.CreateStore(Loc, Addr);
+        } else if (r.isComplex())
           // FIXME: implement
           ErrorUnsupported(BE, "complex in block literal");
         else if (r.isAggregate())
@@ -426,6 +441,55 @@
                   Func, Args);
 }
 
+llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
+  uint64_t &offset = BlockDecls[E->getDecl()];
+
+  const llvm::Type *Ty;
+  Ty = CGM.getTypes().ConvertType(E->getDecl()->getType());
+
+  // FIXME: add support for copy/dispose helpers.
+  if (1 && E->isByRef())
+    ErrorUnsupported(E, "__block variable in block literal");
+  else if (E->getType()->isBlockPointerType())
+    ErrorUnsupported(E, "block pointer in block literal");
+  else if (E->getDecl()->getAttr<ObjCNSObjectAttr>() || 
+           getContext().isObjCNSObjectType(E->getType()))
+    ErrorUnsupported(E, "__attribute__((NSObject)) variable in block "
+                     "literal");
+  else if (getContext().isObjCObjectPointerType(E->getType()))
+    ErrorUnsupported(E, "Objective-C variable in block literal");
+
+  // See if we have already allocated an offset for this variable.
+  if (offset == 0) {
+    // if not, allocate one now.
+    offset = getBlockOffset(E);
+  }
+
+  llvm::Value *BlockLiteral = LoadBlockStruct();
+  llvm::Value *V = Builder.CreateGEP(BlockLiteral,
+                                     llvm::ConstantInt::get(llvm::Type::Int64Ty,
+                                                            offset),
+                                     "tmp");
+  if (E->isByRef()) {
+    bool needsCopyDispose = BlockRequiresCopying(E->getType());
+    uint64_t Align = getContext().getDeclAlignInBytes(E->getDecl());
+    const llvm::Type *PtrStructTy
+      = llvm::PointerType::get(BuildByRefType(E->getType(), Align), 0);
+    Ty = PtrStructTy;
+    Ty = llvm::PointerType::get(Ty, 0);
+    V = Builder.CreateBitCast(V, Ty);
+    V = Builder.CreateLoad(V, false);
+    V = Builder.CreateStructGEP(V, 1, "forwarding");
+    V = Builder.CreateLoad(V, false);
+    V = Builder.CreateBitCast(V, PtrStructTy);
+    V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x");
+  } else {
+    Ty = llvm::PointerType::get(Ty, 0);
+    V = Builder.CreateBitCast(V, Ty);
+  }
+  return V;
+}
+
 llvm::Constant *
 CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
   // Generate the block descriptor.
@@ -589,3 +653,23 @@
   BlockOffset += Size;
   return BlockOffset-Size;
 }
+
+llvm::Value *CodeGenFunction::BuildCopyHelper(int flag) {
+  const llvm::PointerType *PtrToInt8Ty
+    = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+  // FIXME: implement
+  llvm::Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty, 43);
+  V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
+  V = Builder.CreateBitCast(V, PtrToInt8Ty, "tmp");
+  return V;
+}
+
+llvm::Value *CodeGenFunction::BuildDestroyHelper(int flag) {
+  const llvm::PointerType *PtrToInt8Ty
+    = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+  // FIXME: implement
+  llvm::Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty, 44);
+  V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
+  V = Builder.CreateBitCast(V, PtrToInt8Ty, "tmp");
+  return V;
+}

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=66007&r1=66006&r2=66007&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Mar  3 21:23:46 2009
@@ -21,6 +21,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/GlobalVariable.h"
 #include "llvm/Intrinsics.h"
+#include "llvm/Target/TargetData.h"
 #include "llvm/Type.h"
 using namespace clang;
 using namespace CodeGen;
@@ -188,20 +189,61 @@
   }
 }
   
+/// BuildByRefType - This routine changes a __block variable declared as T x
+///   into:
+///
+///      struct {
+///        void *__isa;
+///        void *__forwarding;
+///        int32_t __flags;
+///        int32_t __size;
+///        void *__copy_helper;
+///        void *__destroy_helper;
+///        T x;
+///      } x
+///
+/// Align is the alignment needed in bytes for x.
+const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty,
+                                                  uint64_t Align) {
+  const llvm::Type *LTy = ConvertType(Ty);
+  bool needsCopyDispose = BlockRequiresCopying(Ty);
+  std::vector<const llvm::Type *> Types(needsCopyDispose*2+5);
+  const llvm::PointerType *PtrToInt8Ty
+    = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+  Types[0] = PtrToInt8Ty;
+  Types[1] = PtrToInt8Ty;
+  Types[2] = llvm::Type::Int32Ty;
+  Types[3] = llvm::Type::Int32Ty;
+  if (needsCopyDispose) {
+    Types[4] = PtrToInt8Ty;
+    Types[5] = PtrToInt8Ty;
+  }
+  // FIXME: Align this on at least an Align boundary.
+  Types[needsCopyDispose*2 + 4] = LTy;
+  return llvm::StructType::get(Types, false);
+}
+
 /// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
 /// variable declaration with auto, register, or no storage class specifier.
 /// These turn into simple stack objects, or GlobalValues depending on target.
 void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
   QualType Ty = D.getType();
+  bool isByRef = D.getAttr<BlocksAttr>();
 
   llvm::Value *DeclPtr;
   if (Ty->isConstantSizeType()) {
     if (!Target.useGlobalsForAutomaticVariables()) {
       // A normal fixed sized variable becomes an alloca in the entry block.
       const llvm::Type *LTy = ConvertType(Ty);
+      if (isByRef)
+        LTy = BuildByRefType(Ty, getContext().getDeclAlignInBytes(&D));
       llvm::AllocaInst *Alloc =
         CreateTempAlloca(LTy, CGM.getMangledName(&D));
-      Alloc->setAlignment(getContext().getDeclAlignInBytes(&D));
+      if (isByRef)
+        Alloc->setAlignment(std::max(getContext().getDeclAlignInBytes(&D),
+                                     getContext().getTypeAlign(getContext().VoidPtrTy) / 8));
+      else
+        Alloc->setAlignment(getContext().getDeclAlignInBytes(&D));
       DeclPtr = Alloc;
     } else {
       // Targets that don't support recursion emit locals as globals.
@@ -259,18 +301,77 @@
   // Emit debug info for local var declaration.
   if (CGDebugInfo *DI = getDebugInfo()) {
     DI->setLocation(D.getLocation());
-    DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
+    if (isByRef) {
+      llvm::Value *Loc;
+      bool needsCopyDispose = BlockRequiresCopying(Ty);
+      // FIXME: I think we need to indirect through the forwarding pointer first
+      Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x");
+      DI->EmitDeclareOfAutoVariable(&D, Loc, Builder);
+    } else
+      DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
   }
 
   // If this local has an initializer, emit it now.
   if (const Expr *Init = D.getInit()) {
+    llvm::Value *Loc = DeclPtr;
+    if (isByRef) {
+      bool needsCopyDispose = BlockRequiresCopying(Ty);
+      Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x");
+    }
     if (!hasAggregateLLVMType(Init->getType())) {
       llvm::Value *V = EmitScalarExpr(Init);
-      Builder.CreateStore(V, DeclPtr, D.getType().isVolatileQualified());
+      Builder.CreateStore(V, Loc, D.getType().isVolatileQualified());
     } else if (Init->getType()->isAnyComplexType()) {
-      EmitComplexExprIntoAddr(Init, DeclPtr, D.getType().isVolatileQualified());
+      EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified());
     } else {
-      EmitAggExpr(Init, DeclPtr, D.getType().isVolatileQualified());
+      EmitAggExpr(Init, Loc, D.getType().isVolatileQualified());
+    }
+  }
+  if (isByRef) {
+    const llvm::PointerType *PtrToInt8Ty
+      = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+    llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0);
+    llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1);
+    llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2);
+    llvm::Value *size_field = Builder.CreateStructGEP(DeclPtr, 3);
+    llvm::Value *V;
+    int flag = 0;
+    int flags = 0;
+
+    if (Ty->isBlockPointerType()) {
+      flag |= BLOCK_FIELD_IS_BLOCK;
+      flags |= BLOCK_HAS_COPY_DISPOSE;
+    } else if (BlockRequiresCopying(Ty)) {
+      flags |= BLOCK_HAS_COPY_DISPOSE;
+      flag |= BLOCK_FIELD_IS_OBJECT;
+    }
+    // FIXME: Need to set BLOCK_FIELD_IS_WEAK as appropriate.
+
+    int isa = 0;
+    if (flag&BLOCK_FIELD_IS_WEAK)
+      isa = 1;
+    V = llvm::ConstantInt::get(llvm::Type::Int32Ty, isa);
+    V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
+    Builder.CreateStore(V, isa_field);
+
+    V = Builder.CreateBitCast(DeclPtr, PtrToInt8Ty, "tmp");
+    Builder.CreateStore(V, forwarding_field);
+
+    V = llvm::ConstantInt::get(llvm::Type::Int32Ty, flags);
+    Builder.CreateStore(V, flags_field);
+
+    const llvm::Type *V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
+    V = llvm::ConstantInt::get(llvm::Type::Int32Ty, CGM.getTargetData().getTypeStoreSizeInBits(V1) / 8);
+    Builder.CreateStore(V, size_field);
+
+    if (flags & BLOCK_HAS_COPY_DISPOSE) {
+      llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
+      llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
+
+      Builder.CreateStore(BuildCopyHelper(flag), copy_helper);
+
+      Builder.CreateStore(BuildDestroyHelper(flag), destroy_helper);
     }
   }
 

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=66007&r1=66006&r2=66007&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Mar  3 21:23:46 2009
@@ -636,6 +636,17 @@
       // local static?
       if (!VD->hasLocalStorage())
         attr = getContext().getObjCGCAttrKind(E->getType());
+      if (VD->getAttr<BlocksAttr>()) {
+        bool needsCopyDispose = BlockRequiresCopying(VD->getType());
+        const llvm::Type *PtrStructTy = V->getType();
+        const llvm::Type *Ty = PtrStructTy;
+        Ty = llvm::PointerType::get(Ty, 0);
+        V = Builder.CreateStructGEP(V, 1, "forwarding");
+        V = Builder.CreateBitCast(V, Ty);
+        V = Builder.CreateLoad(V, false);
+        V = Builder.CreateBitCast(V, PtrStructTy);
+        V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x");
+      }
       LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr);
     }
     LValue::SetObjCNonGC(LV, VD->hasLocalStorage());
@@ -667,45 +678,6 @@
   return LValue::MakeAddr(GetAddrOfBlockDecl(E), 0);
 }
 
-llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
-  // FIXME: ensure we don't need copy/dispose.
-  uint64_t &offset = BlockDecls[E->getDecl()];
-
-  const llvm::Type *Ty;
-  Ty = CGM.getTypes().ConvertType(E->getDecl()->getType());
-
-  if (E->isByRef())
-    ErrorUnsupported(E, "__block variable in block literal");
-  else if (E->getType()->isBlockPointerType())
-    ErrorUnsupported(E, "block pointer in block literal");
-  else if (E->getDecl()->getAttr<ObjCNSObjectAttr>() || 
-           getContext().isObjCNSObjectType(E->getType()))
-    ErrorUnsupported(E, "__attribute__((NSObject)) variable in block "
-                     "literal");
-  else if (getContext().isObjCObjectPointerType(E->getType()))
-    ErrorUnsupported(E, "Objective-C variable in block literal");
-
-  // See if we have already allocated an offset for this variable.
-  if (offset == 0) {
-    // if not, allocate one now.
-    offset = getBlockOffset(E);
-  }
-
-  llvm::Value *BlockLiteral = LoadBlockStruct();
-  llvm::Value *V = Builder.CreateGEP(BlockLiteral,
-                                     llvm::ConstantInt::get(llvm::Type::Int64Ty,
-                                                            offset),
-                                     "tmp");
-  Ty = llvm::PointerType::get(Ty, 0);
-  if (E->isByRef())
-    Ty = llvm::PointerType::get(Ty, 0);
-  V = Builder.CreateBitCast(V, Ty);
-  if (E->isByRef())
-    V = Builder.CreateLoad(V, false, "tmp");
-
-  return V;
-}
-
 LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
   // __extension__ doesn't affect lvalue-ness.
   if (E->getOpcode() == UnaryOperator::Extension)

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=66007&r1=66006&r2=66007&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Mar  3 21:23:46 2009
@@ -264,6 +264,30 @@
   //                                  Block Bits
   //===--------------------------------------------------------------------===//
 
+  enum {
+    BLOCK_FIELD_IS_OBJECT   =  3,  /* id, NSObject, __attribute__((NSObject)),
+                                      block, ... */
+    BLOCK_FIELD_IS_BLOCK    =  7,  /* a block variable */
+    BLOCK_FIELD_IS_BYREF    =  8,  /* the on stack structure holding the __block
+                                      variable */
+    BLOCK_FIELD_IS_WEAK     = 16,  /* declared __weak, only used in byref copy
+                                      helpers */
+    BLOCK_BYREF_CALLER      = 128  /* called from __block (byref) copy/dispose
+                                      support routines */
+  };
+
+  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::Value *BuildCopyHelper(int flag);
+  llvm::Value *BuildDestroyHelper(int flag);
+
   llvm::Value *BuildBlockLiteralTmp(const BlockExpr *);
   llvm::Constant *BuildDescriptorBlockDecl(uint64_t Size);
 
@@ -319,6 +343,15 @@
 
   llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
 
+  const llvm::Type *BuildByRefType(QualType Ty, uint64_t Align);
+  bool BlockRequiresCopying(QualType Ty) {
+    if (Ty->isBlockPointerType())
+      return true;
+    if (getContext().isObjCNSObjectType(Ty))
+      return true;
+    return false;
+  }
+
   void GenerateCode(const FunctionDecl *FD,
                     llvm::Function *Fn);
   void StartFunction(const Decl *D, QualType RetTy,

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=66007&r1=66006&r2=66007&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Mar  3 21:23:46 2009
@@ -139,6 +139,15 @@
   /// strings. This value has type int * but is actually an Obj-C class pointer.
   llvm::Constant *CFConstantStringClassRef;
 
+  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)
+  };
+
   /// NSConcreteGlobalBlock - Cached reference to the class pointer for global
   /// blocks.
   llvm::Constant *NSConcreteGlobalBlock;





More information about the cfe-commits mailing list