[cfe-commits] r125555 - in /cfe/trunk: lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGRecordLayout.h lib/CodeGen/CGRecordLayoutBuilder.cpp test/CodeGenCXX/pointers-to-data-members.cpp

John McCall rjmccall at apple.com
Mon Feb 14 22:40:56 PST 2011


Author: rjmccall
Date: Tue Feb 15 00:40:56 2011
New Revision: 125555

URL: http://llvm.org/viewvc/llvm-project?rev=125555&view=rev
Log:
Perform zero-initialization of virtual base classes when emitting   
a zero constant for a complete class.  rdar://problem/8424975

To make this happen, track the field indexes for virtual bases
in the complete object.  I'm curious whether we might be better
off making CGRecordLayoutBuilder *much* more reliant on
ASTRecordLayout;  we're currently duplicating an awful lot of the ABI
layout logic.


Modified:
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGRecordLayout.h
    cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
    cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Tue Feb 15 00:40:56 2011
@@ -1036,87 +1036,122 @@
   }
 }
 
-static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
-                                        const CXXRecordDecl *RD) {
-  QualType T = CGM.getContext().getTagDeclType(RD);
-
-  const llvm::StructType *STy =
-    cast<llvm::StructType>(CGM.getTypes().ConvertTypeForMem(T));
-  unsigned NumElements = STy->getNumElements();
-  std::vector<llvm::Constant *> Elements(NumElements);
-
-  const CGRecordLayout &Layout = CGM.getTypes().getCGRecordLayout(RD);
+static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
+                                               const llvm::Type *baseType,
+                                               const CXXRecordDecl *base);
 
-  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
-       E = RD->bases_end(); I != E; ++I) {
+static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
+                                        const CXXRecordDecl *record,
+                                        bool asCompleteObject) {
+  const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record);
+  const llvm::StructType *structure =
+    (asCompleteObject ? layout.getLLVMType()
+                      : layout.getBaseSubobjectLLVMType());
+
+  unsigned numElements = structure->getNumElements();
+  std::vector<llvm::Constant *> elements(numElements);
+
+  // Fill in all the bases.
+  for (CXXRecordDecl::base_class_const_iterator
+         I = record->bases_begin(), E = record->bases_end(); I != E; ++I) {
     if (I->isVirtual()) {
-      // Ignore virtual bases.
+      // Ignore virtual bases; if we're laying out for a complete
+      // object, we'll lay these out later.
       continue;
     }
 
-    const CXXRecordDecl *BaseDecl = 
-      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+    const CXXRecordDecl *base = 
+      cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
 
     // Ignore empty bases.
-    if (BaseDecl->isEmpty())
+    if (base->isEmpty())
       continue;
     
-    // Ignore bases that don't have any pointer to data members.
-    if (CGM.getTypes().isZeroInitializable(BaseDecl))
-      continue;
-
-    unsigned BaseFieldNo = Layout.getNonVirtualBaseLLVMFieldNo(BaseDecl);
-    const llvm::Type *BaseTy = STy->getElementType(BaseFieldNo);
-
-    if (isa<llvm::StructType>(BaseTy)) {
-      // We can just emit the base as a null constant.
-      Elements[BaseFieldNo] = EmitNullConstant(CGM, BaseDecl);
-      continue;
-    }
-
-    // Some bases are represented as arrays of i8 if the size of the
-    // base is smaller than its corresponding LLVM type.
-    // Figure out how many elements this base array has.
-    const llvm::ArrayType *BaseArrayTy =  cast<llvm::ArrayType>(BaseTy);
-    unsigned NumBaseElements = BaseArrayTy->getNumElements();
-
-    // Fill in null data member pointers.
-    std::vector<llvm::Constant *> BaseElements(NumBaseElements);
-    FillInNullDataMemberPointers(CGM, I->getType(), BaseElements, 0);
-
-    // Now go through all other elements and zero them out.
-    if (NumBaseElements) {
-      const llvm::Type* Int8Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
-      llvm::Constant *Zero = llvm::Constant::getNullValue(Int8Ty);
-      for (unsigned I = 0; I != NumBaseElements; ++I) {
-        if (!BaseElements[I])
-          BaseElements[I] = Zero;
-      }
-    }
-      
-    Elements[BaseFieldNo] = llvm::ConstantArray::get(BaseArrayTy, BaseElements);
+    unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
+    const llvm::Type *baseType = structure->getElementType(fieldIndex);
+    elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
   }
 
-  // Visit all fields.
-  for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
-       I != E; ++I) {
-    const FieldDecl *FD = *I;
+  // Fill in all the fields.
+  for (RecordDecl::field_iterator I = record->field_begin(),
+         E = record->field_end(); I != E; ++I) {
+    const FieldDecl *field = *I;
     
     // Ignore bit fields.
-    if (FD->isBitField())
+    if (field->isBitField())
       continue;
     
-    unsigned FieldNo = Layout.getLLVMFieldNo(FD);
-    Elements[FieldNo] = CGM.EmitNullConstant(FD->getType());
+    unsigned fieldIndex = layout.getLLVMFieldNo(field);
+    elements[fieldIndex] = CGM.EmitNullConstant(field->getType());
+  }
+
+  // Fill in the virtual bases, if we're working with the complete object.
+  if (asCompleteObject) {
+    for (CXXRecordDecl::base_class_const_iterator
+           I = record->vbases_begin(), E = record->vbases_end(); I != E; ++I) {
+      const CXXRecordDecl *base = 
+        cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+
+      // Ignore empty bases.
+      if (base->isEmpty())
+        continue;
+
+      unsigned fieldIndex = layout.getVirtualBaseIndex(base);
+
+      // We might have already laid this field out.
+      if (elements[fieldIndex]) continue;
+
+      const llvm::Type *baseType = structure->getElementType(fieldIndex);
+      elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
+    }
   }
 
   // Now go through all other fields and zero them out.
-  for (unsigned i = 0; i != NumElements; ++i) {
-    if (!Elements[i])
-      Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i));
+  for (unsigned i = 0; i != numElements; ++i) {
+    if (!elements[i])
+      elements[i] = llvm::Constant::getNullValue(structure->getElementType(i));
   }
   
-  return llvm::ConstantStruct::get(STy, Elements);
+  return llvm::ConstantStruct::get(structure, elements);
+}
+
+/// Emit the null constant for a base subobject.
+static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
+                                               const llvm::Type *baseType,
+                                               const CXXRecordDecl *base) {
+  const CGRecordLayout &baseLayout = CGM.getTypes().getCGRecordLayout(base);
+
+  // Just zero out bases that don't have any pointer to data members.
+  if (baseLayout.isZeroInitializableAsBase())
+    return llvm::Constant::getNullValue(baseType);
+
+  // If the base type is a struct, we can just use its null constant.
+  if (isa<llvm::StructType>(baseType)) {
+    return EmitNullConstant(CGM, base, /*complete*/ false);
+  }
+
+  // Otherwise, some bases are represented as arrays of i8 if the size
+  // of the base is smaller than its corresponding LLVM type.  Figure
+  // out how many elements this base array has.
+  const llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType);
+  unsigned numBaseElements = baseArrayType->getNumElements();
+
+  // Fill in null data member pointers.
+  std::vector<llvm::Constant *> baseElements(numBaseElements);
+  FillInNullDataMemberPointers(CGM, CGM.getContext().getTypeDeclType(base),
+                               baseElements, 0);
+
+  // Now go through all other elements and zero them out.
+  if (numBaseElements) {
+    const llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+    llvm::Constant *i8_zero = llvm::Constant::getNullValue(i8);
+    for (unsigned i = 0; i != numBaseElements; ++i) {
+      if (!baseElements[i])
+        baseElements[i] = i8_zero;
+    }
+  }
+      
+  return llvm::ConstantArray::get(baseArrayType, baseElements);
 }
 
 llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
@@ -1140,7 +1175,7 @@
 
   if (const RecordType *RT = T->getAs<RecordType>()) {
     const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-    return ::EmitNullConstant(*this, RD);
+    return ::EmitNullConstant(*this, RD, /*complete object*/ true);
   }
 
   assert(T->isMemberPointerType() && "Should only see member pointers here!");

Modified: cfe/trunk/lib/CodeGen/CGRecordLayout.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayout.h?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayout.h (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayout.h Tue Feb 15 00:40:56 2011
@@ -173,12 +173,13 @@
   void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
 
 private:
-  /// The LLVM type corresponding to this record layout.
-  llvm::PATypeHolder LLVMType;
-
-  /// The LLVM type for the non-virtual part of this record layout, used for
-  /// laying out the record as a base.
-  llvm::PATypeHolder NonVirtualBaseLLVMType;
+  /// The LLVM type corresponding to this record layout; used when
+  /// laying it out as a complete object.
+  llvm::PATypeHolder CompleteObjectType;
+
+  /// The LLVM type for the non-virtual part of this record layout;
+  /// used when laying it out as a base subobject.
+  llvm::PATypeHolder BaseSubobjectType;
 
   /// Map from (non-bit-field) struct field to the corresponding llvm struct
   /// type field no. This info is populated by record builder.
@@ -190,26 +191,41 @@
 
   // FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single
   // map for both virtual and non virtual bases.
-  llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBaseFields;
+  llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
+
+  /// Map from virtual bases to their field index in the complete object.
+  llvm::DenseMap<const CXXRecordDecl *, unsigned> CompleteObjectVirtualBases;
 
-  /// Whether one of the fields in this record layout is a pointer to data
-  /// member, or a struct that contains pointer to data member.
+  /// False if any direct or indirect subobject of this class, when
+  /// considered as a complete object, requires a non-zero bitpattern
+  /// when zero-initialized.
   bool IsZeroInitializable : 1;
 
+  /// False if any direct or indirect subobject of this class, when
+  /// considered as a base subobject, requires a non-zero bitpattern
+  /// when zero-initialized.
+  bool IsZeroInitializableAsBase : 1;
+
 public:
-  CGRecordLayout(const llvm::StructType *LLVMType,
-                 const llvm::StructType *NonVirtualBaseLLVMType,
-                 bool IsZeroInitializable)
-    : LLVMType(LLVMType), NonVirtualBaseLLVMType(NonVirtualBaseLLVMType), 
-    IsZeroInitializable(IsZeroInitializable) {}
+  CGRecordLayout(const llvm::StructType *CompleteObjectType,
+                 const llvm::StructType *BaseSubobjectType,
+                 bool IsZeroInitializable,
+                 bool IsZeroInitializableAsBase)
+    : CompleteObjectType(CompleteObjectType),
+      BaseSubobjectType(BaseSubobjectType),
+      IsZeroInitializable(IsZeroInitializable),
+      IsZeroInitializableAsBase(IsZeroInitializableAsBase) {}
 
-  /// \brief Return the LLVM type associated with this record.
+  /// \brief Return the "complete object" LLVM type associated with
+  /// this record.
   const llvm::StructType *getLLVMType() const {
-    return cast<llvm::StructType>(LLVMType.get());
+    return cast<llvm::StructType>(CompleteObjectType.get());
   }
 
-  const llvm::StructType *getNonVirtualBaseLLVMType() const {
-    return cast<llvm::StructType>(NonVirtualBaseLLVMType.get());
+  /// \brief Return the "base subobject" LLVM type associated with
+  /// this record.
+  const llvm::StructType *getBaseSubobjectLLVMType() const {
+    return cast<llvm::StructType>(BaseSubobjectType.get());
   }
 
   /// \brief Check whether this struct can be C++ zero-initialized
@@ -218,6 +234,12 @@
     return IsZeroInitializable;
   }
 
+  /// \brief Check whether this struct can be C++ zero-initialized
+  /// with a zeroinitializer when considered as a base subobject.
+  bool isZeroInitializableAsBase() const {
+    return IsZeroInitializableAsBase;
+  }
+
   /// \brief Return llvm::StructType element number that corresponds to the
   /// field FD.
   unsigned getLLVMFieldNo(const FieldDecl *FD) const {
@@ -227,8 +249,15 @@
   }
 
   unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const {
-    assert(NonVirtualBaseFields.count(RD) && "Invalid non-virtual base!");
-    return NonVirtualBaseFields.lookup(RD);
+    assert(NonVirtualBases.count(RD) && "Invalid non-virtual base!");
+    return NonVirtualBases.lookup(RD);
+  }
+
+  /// \brief Return the LLVM field index corresponding to the given
+  /// virtual base.  Only valid when operating on the complete object.
+  unsigned getVirtualBaseIndex(const CXXRecordDecl *base) const {
+    assert(CompleteObjectVirtualBases.count(base) && "Invalid virtual base!");
+    return CompleteObjectVirtualBases.lookup(base);
   }
 
   /// \brief Return the BitFieldInfo that corresponds to the field FD.
@@ -236,7 +265,7 @@
     assert(FD->isBitField() && "Invalid call for non bit-field decl!");
     llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
       it = BitFields.find(FD);
-    assert(it != BitFields.end()  && "Unable to find bitfield info");
+    assert(it != BitFields.end() && "Unable to find bitfield info");
     return it->second;
   }
 

Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Tue Feb 15 00:40:56 2011
@@ -33,9 +33,10 @@
 class CGRecordLayoutBuilder {
 public:
   /// FieldTypes - Holds the LLVM types that the struct is created from.
+  /// 
   std::vector<const llvm::Type *> FieldTypes;
 
-  /// NonVirtualBaseFieldTypes - Holds the LLVM types for the non-virtual part
+  /// BaseSubobjectType - Holds the LLVM type for the non-virtual part
   /// of the struct. For example, consider:
   ///
   /// struct A { int i; };
@@ -47,22 +48,19 @@
   ///
   /// And the LLVM type of the non-virtual base struct will be
   /// %struct.C.base = type { i32 (...)**, %struct.A, i32 }
-  std::vector<const llvm::Type *> NonVirtualBaseFieldTypes;
+  ///
+  /// This only gets initialized if the base subobject type is
+  /// different from the complete-object type.
+  const llvm::StructType *BaseSubobjectType;
 
-  /// NonVirtualBaseTypeIsSameAsCompleteType - Whether the non-virtual part of
-  /// the struct is equivalent to the complete struct.
-  bool NonVirtualBaseTypeIsSameAsCompleteType;
-  
-  /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
-  typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
-  llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
-
-  /// LLVMBitFieldInfo - Holds location and size information about a bit field.
-  typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo;
-  llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+  /// FieldInfo - Holds a field and its corresponding LLVM field number.
+  llvm::DenseMap<const FieldDecl *, unsigned> Fields;
+
+  /// BitFieldInfo - Holds location and size information about a bit field.
+  llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
 
-  typedef std::pair<const CXXRecordDecl *, unsigned> LLVMBaseInfo;
-  llvm::SmallVector<LLVMBaseInfo, 16> LLVMNonVirtualBases;
+  llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
+  llvm::DenseMap<const CXXRecordDecl *, unsigned> VirtualBases;
 
   /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
   /// primary base classes for some other direct or indirect base class.
@@ -75,6 +73,7 @@
   /// IsZeroInitializable - Whether this struct can be C++
   /// zero-initialized with an LLVM zeroinitializer.
   bool IsZeroInitializable;
+  bool IsZeroInitializableAsBase;
 
   /// Packed - Whether the resulting LLVM struct will be packed or not.
   bool Packed;
@@ -148,6 +147,7 @@
   
   /// AppendBytes - Append a given number of bytes to the record.
   void AppendBytes(uint64_t NumBytes);
+  void AppendBytes(CharUnits numBytes) { AppendBytes(numBytes.getQuantity()); }
 
   /// AppendTailPadding - Append enough tail padding so that the type will have
   /// the passed size.
@@ -162,13 +162,13 @@
   /// CheckZeroInitializable - Check if the given type contains a pointer
   /// to data member.
   void CheckZeroInitializable(QualType T);
-  void CheckZeroInitializable(const CXXRecordDecl *RD);
 
 public:
   CGRecordLayoutBuilder(CodeGenTypes &Types)
-    : NonVirtualBaseTypeIsSameAsCompleteType(false), IsZeroInitializable(true),
-    Packed(false), Types(Types), Alignment(0), BitsAvailableInLastField(0),
-    NextFieldOffsetInBytes(0) { }
+    : BaseSubobjectType(0),
+      IsZeroInitializable(true), IsZeroInitializableAsBase(true),
+      Packed(false), Types(Types), Alignment(0),
+      BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
 
   /// Layout - Will layout a RecordDecl.
   void Layout(const RecordDecl *D);
@@ -193,9 +193,10 @@
   Packed = true;
   NextFieldOffsetInBytes = 0;
   FieldTypes.clear();
-  LLVMFields.clear();
-  LLVMBitFields.clear();
-  LLVMNonVirtualBases.clear();
+  Fields.clear();
+  BitFields.clear();
+  NonVirtualBases.clear();
+  VirtualBases.clear();
 
   LayoutFields(D);
 }
@@ -339,9 +340,8 @@
   }
 
   // Add the bit field info.
-  LLVMBitFields.push_back(
-    LLVMBitFieldInfo(D, CGBitFieldInfo::MakeInfo(Types, D, FieldOffset,
-                                                 FieldSize)));
+  BitFields.insert(std::make_pair(D,
+                   CGBitFieldInfo::MakeInfo(Types, D, FieldOffset, FieldSize)));
 
   AppendBytes(NumBytesToAppend);
 
@@ -401,7 +401,7 @@
   AppendPadding(FieldOffsetInBytes, TypeAlignment);
 
   // Now append the field.
-  LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size()));
+  Fields[D] = FieldTypes.size();
   AppendField(FieldOffsetInBytes, Ty);
 
   return true;
@@ -426,14 +426,13 @@
       FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend);
 
     // Add the bit field info.
-    LLVMBitFields.push_back(
-      LLVMBitFieldInfo(Field, CGBitFieldInfo::MakeInfo(Types, Field,
-                                                       0, FieldSize)));
+    BitFields.insert(std::make_pair(Field,
+                         CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize)));
     return FieldTy;
   }
 
   // This is a regular union field.
-  LLVMFields.push_back(LLVMFieldInfo(Field, 0));
+  Fields[Field] = 0;
   return Types.ConvertTypeForMemRecursive(Field->getType());
 }
 
@@ -495,41 +494,51 @@
     AppendPadding(RecordSize, Align);
 }
 
-void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *BaseDecl,
-                                       uint64_t BaseOffset) {
-  CheckZeroInitializable(BaseDecl);
-
-  const ASTRecordLayout &Layout = 
-    Types.getContext().getASTRecordLayout(BaseDecl);
-  
-  CharUnits NonVirtualSize = Layout.getNonVirtualSize();
-  
-  AppendPadding(BaseOffset / 8, 1);
-  
-  // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can.
-  AppendBytes(NonVirtualSize.getQuantity());
+void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
+                                       uint64_t baseOffsetInBits) {
+  uint64_t baseOffsetInBytes = baseOffsetInBits / 8;
+  AppendPadding(baseOffsetInBytes, 1);
+
+  const ASTRecordLayout &baseASTLayout
+    = Types.getContext().getASTRecordLayout(base);
+
+  // FIXME: use a better type than [sizeof(base) x i8].
+  // We could use the base layout's subobject type as the actualy
+  // subobject type in the layout if its size is the nvsize of the
+  // base, or if we'd need padding out to the enclosing object anyhow.
+  AppendBytes(baseASTLayout.getNonVirtualSize());
 }
 
-void
-CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *BaseDecl,
-                                         uint64_t BaseOffset) {
+void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
+                                                 uint64_t baseOffsetInBits) {
   // Ignore empty bases.
-  if (BaseDecl->isEmpty())
-    return;
+  if (base->isEmpty()) return;
 
-  CheckZeroInitializable(BaseDecl);
+  const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
+  if (IsZeroInitializableAsBase) {
+    assert(IsZeroInitializable &&
+           "class zero-initializable as base but not as complete object");
 
-  const ASTRecordLayout &Layout = 
-    Types.getContext().getASTRecordLayout(BaseDecl);
+    IsZeroInitializable = IsZeroInitializableAsBase =
+      baseLayout.isZeroInitializableAsBase();
+  }
 
-  CharUnits NonVirtualSize = Layout.getNonVirtualSize();
+  LayoutBase(base, baseOffsetInBits);
+  NonVirtualBases[base] = (FieldTypes.size() - 1);
+}
 
-  AppendPadding(BaseOffset / 8, 1);
-  
-  // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can.
-  AppendBytes(NonVirtualSize.getQuantity());
+void
+CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *base,
+                                         uint64_t baseOffsetInBits) {
+  // Ignore empty bases.
+  if (base->isEmpty()) return;
+
+  const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
+  if (IsZeroInitializable)
+    IsZeroInitializable = baseLayout.isZeroInitializableAsBase();
 
-  // FIXME: Add the vbase field info.
+  LayoutBase(base, baseOffsetInBits);
+  VirtualBases[base] = (FieldTypes.size() - 1);
 }
 
 /// LayoutVirtualBases - layout the non-virtual bases of a record decl.
@@ -561,18 +570,6 @@
   }
 }
 
-void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
-                                                 uint64_t BaseOffset) {
-  // Ignore empty bases.
-  if (BaseDecl->isEmpty())
-    return;
-
-  LayoutBase(BaseDecl, BaseOffset);
-
-  // Append the base field.
-  LLVMNonVirtualBases.push_back(LLVMBaseInfo(BaseDecl, FieldTypes.size() - 1));
-}
-
 void
 CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
                                              const ASTRecordLayout &Layout) {
@@ -618,37 +615,40 @@
 CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
   const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD);
 
-
   CharUnits NonVirtualSize  = Layout.getNonVirtualSize();
   CharUnits NonVirtualAlign = Layout.getNonVirtualAlign();
   uint64_t AlignedNonVirtualTypeSize =
     NonVirtualSize.RoundUpToAlignment(NonVirtualAlign).getQuantity();
   
-  
   // First check if we can use the same fields as for the complete class.
   uint64_t RecordSize = Layout.getSize().getQuantity();
-  if (AlignedNonVirtualTypeSize == RecordSize) {
-    NonVirtualBaseTypeIsSameAsCompleteType = true;
+  if (AlignedNonVirtualTypeSize == RecordSize)
     return true;
-  }
 
   // Check if we need padding.
   uint64_t AlignedNextFieldOffset =
     llvm::RoundUpToAlignment(NextFieldOffsetInBytes, 
                              getAlignmentAsLLVMStruct());
 
-  if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize)
+  if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) {
+    assert(!Packed && "cannot layout even as packed struct");
     return false; // Needs packing.
+  }
 
-  NonVirtualBaseFieldTypes = FieldTypes;
+  bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset);
+  if (needsPadding) {
+    uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
+    FieldTypes.push_back(getByteArrayType(NumBytes));
+  }
 
-  if (AlignedNonVirtualTypeSize == AlignedNextFieldOffset) {
-    // We don't need any padding.
-    return true;
+  BaseSubobjectType = llvm::StructType::get(Types.getLLVMContext(),
+                                            FieldTypes, Packed);
+
+  if (needsPadding) {
+    // Pull the padding back off.
+    FieldTypes.pop_back();
   }
 
-  uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
-  NonVirtualBaseFieldTypes.push_back(getByteArrayType(NumBytes));
   return true;
 }
 
@@ -777,36 +777,29 @@
   return MaxAlignment;
 }
 
+/// Merge in whether a field of the given type is zero-initializable.
 void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) {
   // This record already contains a member pointer.
-  if (!IsZeroInitializable)
+  if (!IsZeroInitializableAsBase)
     return;
 
   // Can only have member pointers if we're compiling C++.
   if (!Types.getContext().getLangOptions().CPlusPlus)
     return;
 
-  T = Types.getContext().getBaseElementType(T);
+  const Type *elementType = T->getBaseElementTypeUnsafe();
 
-  if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
+  if (const MemberPointerType *MPT = elementType->getAs<MemberPointerType>()) {
     if (!Types.getCXXABI().isZeroInitializable(MPT))
-      IsZeroInitializable = false;
-  } else if (const RecordType *RT = T->getAs<RecordType>()) {
+      IsZeroInitializable = IsZeroInitializableAsBase = false;
+  } else if (const RecordType *RT = elementType->getAs<RecordType>()) {
     const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-    CheckZeroInitializable(RD);
+    const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+    if (!Layout.isZeroInitializable())
+      IsZeroInitializable = IsZeroInitializableAsBase = false;
   }
 }
 
-void CGRecordLayoutBuilder::CheckZeroInitializable(const CXXRecordDecl *RD) {
-  // This record already contains a member pointer.
-  if (!IsZeroInitializable)
-    return;
-
-  const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
-  if (!Layout.isZeroInitializable())
-    IsZeroInitializable = false;
-}
-
 CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
   CGRecordLayoutBuilder Builder(*this);
 
@@ -816,30 +809,25 @@
                                                      Builder.FieldTypes,
                                                      Builder.Packed);
 
+  // If we're in C++, compute the base subobject type.
   const llvm::StructType *BaseTy = 0;
   if (isa<CXXRecordDecl>(D)) {
-    if (Builder.NonVirtualBaseTypeIsSameAsCompleteType)
-      BaseTy = Ty;
-    else if (!Builder.NonVirtualBaseFieldTypes.empty())
-      BaseTy = llvm::StructType::get(getLLVMContext(), 
-                                     Builder.NonVirtualBaseFieldTypes, 
-                                     Builder.Packed);
+    BaseTy = Builder.BaseSubobjectType;
+    if (!BaseTy) BaseTy = Ty;
   }
 
   CGRecordLayout *RL =
-    new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable);
+    new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable,
+                       Builder.IsZeroInitializableAsBase);
 
-  // Add all the non-virtual base field numbers.
-  RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(),
-                                  Builder.LLVMNonVirtualBases.end());
+  RL->NonVirtualBases.swap(Builder.NonVirtualBases);
+  RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases);
 
   // Add all the field numbers.
-  RL->FieldInfo.insert(Builder.LLVMFields.begin(),
-                       Builder.LLVMFields.end());
+  RL->FieldInfo.swap(Builder.Fields);
 
   // Add bitfield info.
-  RL->BitFields.insert(Builder.LLVMBitFields.begin(),
-                       Builder.LLVMBitFields.end());
+  RL->BitFields.swap(Builder.BitFields);
 
   // Dump the layout, if requested.
   if (getContext().getLangOptions().DumpRecordLayouts) {
@@ -913,9 +901,9 @@
 
 void CGRecordLayout::print(llvm::raw_ostream &OS) const {
   OS << "<CGRecordLayout\n";
-  OS << "  LLVMType:" << *LLVMType << "\n";
-  if (NonVirtualBaseLLVMType)
-    OS << "  NonVirtualBaseLLVMType:" << *NonVirtualBaseLLVMType << "\n"; 
+  OS << "  LLVMType:" << *CompleteObjectType << "\n";
+  if (BaseSubobjectType)
+    OS << "  NonVirtualBaseLLVMType:" << *BaseSubobjectType << "\n"; 
   OS << "  IsZeroInitializable:" << IsZeroInitializable << "\n";
   OS << "  BitFields:[\n";
 

Modified: cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp Tue Feb 15 00:40:56 2011
@@ -1,37 +1,41 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck --check-prefix=CHECK-O3 %s
+// RUN: %clang_cc1 %s -emit-llvm -o %t.ll -triple=x86_64-apple-darwin10
+// RUN: FileCheck %s < %t.ll
+// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t.ll
+// RUN: %clang_cc1 %s -emit-llvm -o %t-opt.ll -triple=x86_64-apple-darwin10 -O3
+// RUN: FileCheck --check-prefix=CHECK-O3 %s < %t-opt.ll
+
 struct A { int a; int b; };
 struct B { int b; };
 struct C : B, A { };
 
 // Zero init.
 namespace ZeroInit {
-  // CHECK: @_ZN8ZeroInit1aE = global i64 -1
+  // CHECK-GLOBAL: @_ZN8ZeroInit1aE = global i64 -1
   int A::* a;
   
-  // CHECK: @_ZN8ZeroInit2aaE = global [2 x i64] [i64 -1, i64 -1]
+  // CHECK-GLOBAL: @_ZN8ZeroInit2aaE = global [2 x i64] [i64 -1, i64 -1]
   int A::* aa[2];
   
-  // CHECK: @_ZN8ZeroInit3aaaE = global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]]
+  // CHECK-GLOBAL: @_ZN8ZeroInit3aaaE = global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]]
   int A::* aaa[2][2];
   
-  // CHECK: @_ZN8ZeroInit1bE = global i64 -1,
+  // CHECK-GLOBAL: @_ZN8ZeroInit1bE = global i64 -1,
   int A::* b = 0;
 
-  // CHECK: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 }
+  // CHECK-GLOBAL: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 }
   struct {
     int A::*a;
   } sa;
   void test_sa() { (void) sa; } // force emission
   
-  // CHECK: @_ZN8ZeroInit3ssaE = internal
-  // CHECK: [2 x i64] [i64 -1, i64 -1]
+  // CHECK-GLOBAL: @_ZN8ZeroInit3ssaE = internal
+  // CHECK-GLOBAL: [2 x i64] [i64 -1, i64 -1]
   struct {
     int A::*aa[2];
   } ssa[2];
   void test_ssa() { (void) ssa; }
   
-  // CHECK: @_ZN8ZeroInit2ssE = internal global %1 { %struct.anon { i64 -1 } }
+  // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %1 { %struct.anon { i64 -1 } }
   struct {
     struct {
       int A::*pa;
@@ -51,13 +55,13 @@
   };
 
   struct C : A, B { int j; };
-  // CHECK: @_ZN8ZeroInit1cE = global %"struct.ZeroInit::C" { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
+  // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
   C c;
 }
 
 // PR5674
 namespace PR5674 {
-  // CHECK: @_ZN6PR56742pbE = global i64 4
+  // CHECK-GLOBAL: @_ZN6PR56742pbE = global i64 4
   int A::*pb = &A::b;
 }
 
@@ -168,15 +172,15 @@
   int A::*i;
 };
 
-// FIXME: A::i should be initialized to -1 here.
+// CHECK-GLOBAL: @_ZN12VirtualBases1bE = global {{%.*}} { i32 (...)** null, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
 struct B : virtual A { };
 B b;
 
-// FIXME: A::i should be initialized to -1 here.
+// CHECK-GLOBAL: @_ZN12VirtualBases1cE = global {{%.*}} { i32 (...)** null, i64 -1, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
 struct C : virtual A { int A::*i; };
 C c;
 
-// FIXME: C::A::i should be initialized to -1 here.
+  // CHECK-GLOBAL: @_ZN12VirtualBases1dE = global {{%.*}} { [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i64 -1, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
 struct D : C { int A::*i; };
 D d;
 
@@ -217,3 +221,12 @@
 
 }
 
+namespace test4 {
+  struct A             { int A_i; };
+  struct B : virtual A { int A::*B_p; };
+  struct C : virtual B { int    *C_p; };
+  struct D :         C { int    *D_p; };
+
+  // CHECK-GLOBAL: @_ZN5test41dE = global {{%.*}} { [16 x i8] zeroinitializer, i32* null, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", [4 x i8] zeroinitializer }
+  D d;
+}





More information about the cfe-commits mailing list