]> granicus.if.org Git - clang/commitdiff
Reapply r150631:
authorEric Christopher <echristo@apple.com>
Thu, 16 Feb 2012 22:54:45 +0000 (22:54 +0000)
committerEric Christopher <echristo@apple.com>
Thu, 16 Feb 2012 22:54:45 +0000 (22:54 +0000)
    "Add a completed/incomplete type difference. This allows us to have
    partial types for contexts and forward decls while allowing us to
    complete types later on for debug purposes.

    This piggy-backs on the metadata replacement and rauw changes
    for temporary nodes and takes advantage of the incremental
    support I added in earlier. This allows us to, if we decide,
    to limit adding methods and variables to structures in order
    to limit the amount of debug information output into a .o file.

    The caching is a bit complicated though so any thoughts on
    untangling that are welcome."

with a fix:

 - Remove all RAUW during type construction by adding stub versions
   of types that we later complete.

and some TODOs:

 - Add an RAUW cache for forward declared types so that we can replace
   them at the end of compilation.
 - Remove the code that updates on completed types because we no
   longer need to have that happen. We emit incomplete types on
   purpose and only want to know when we want to complete them.

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

lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGDebugInfo.h
test/CodeGenCXX/debug-info-dup-fwd-decl.cpp

index 34da5f4d998fd45b9e52da488a53e3043919e195..1f733be1a7d150f994e64251e1f92ddfd9903a9a 100644 (file)
@@ -524,11 +524,8 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
 
   if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
     if (!RD->isDependentType()) {
-      llvm::DIDescriptor FDContext =
-        createContextChain(cast<Decl>(RD->getDeclContext()));
-      llvm::DIType Ty = createRecordFwdDecl(RD, FDContext);
-
-      RegionMap[Context] = llvm::WeakVH(Ty);
+      llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
+                                              getOrCreateMainFile());
       return llvm::DIDescriptor(Ty);
     }
   }
@@ -557,7 +554,9 @@ llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
     RecordDecl *RD = RTy->getDecl();
     llvm::DIDescriptor FDContext =
       getContextDescriptor(cast<Decl>(RD->getDeclContext()));
-    return createRecordFwdDecl(RD, FDContext);
+    llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext);
+    TypeCache[PointeeTy.getAsOpaquePtr()] = RetTy;
+    return RetTy;
   }
   return getOrCreateType(PointeeTy, Unit);
 
@@ -654,10 +653,11 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
   // declared.
   unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
   const TypedefNameDecl *TyDecl = Ty->getDecl();
+  
   llvm::DIDescriptor TypedefContext =
     getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
-
-  return  
+  
+  return
     DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
 }
 
@@ -1133,8 +1133,6 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
 
   // Get overall information about the record type for the debug info.
   llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
-  unsigned Line = getLineNumber(RD->getLocation());
-  StringRef RDName = RD->getName();
 
   // Records and classes and unions can all be recursive.  To handle them, we
   // first generate a debug descriptor for the struct as a forward declaration.
@@ -1143,28 +1141,21 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
   // may refer to the forward decl if the struct is recursive) and replace all
   // uses of the forward declaration with the final definition.
 
-  llvm::DIDescriptor RDContext;
-  if (CGM.getCodeGenOpts().LimitDebugInfo)
-    RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
-  else
-    RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
-
-  // If this is just a forward declaration, construct an appropriately
-  // marked node and just return it.
-  if (!RD->getDefinition())
-    return createRecordFwdDecl(RD, RDContext);
-
-  llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
+  llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
 
+  if (FwdDecl.isForwardDecl())
+    return FwdDecl;
+  
   llvm::MDNode *MN = FwdDecl;
   llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
-  // Otherwise, insert it into the TypeCache so that recursive uses will find
-  // it.
-  TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+  
   // Push the struct on region stack.
   LexicalBlockStack.push_back(FwdDeclNode);
   RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
 
+  // Add this to the completed types cache since we're completing it.
+  CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+
   // Convert all the elements.
   SmallVector<llvm::Value *, 16> EltTys;
 
@@ -1196,50 +1187,20 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
   if (RI != RegionMap.end())
     RegionMap.erase(RI);
 
-  uint64_t Size = CGM.getContext().getTypeSize(Ty);
-  uint64_t Align = CGM.getContext().getTypeAlign(Ty);
   llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-  llvm::MDNode *RealDecl = NULL;
-
+  // FIXME: Magic numbers ahoy! These should be changed when we
+  // get some enums in llvm/Analysis/DebugInfo.h to refer to
+  // them.
   if (RD->isUnion())
-    RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
-                                        Size, Align, 0, Elements);
+    MN->replaceOperandWith(10, Elements);
   else if (CXXDecl) {
-    RDName = getClassName(RD);
-     // A class's primary base or the class itself contains the vtable.
-    llvm::MDNode *ContainingType = NULL;
-    const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
-    if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
-      // Seek non virtual primary base root.
-      while (1) {
-        const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
-        const CXXRecordDecl *PBT = BRL.getPrimaryBase();
-        if (PBT && !BRL.isPrimaryBaseVirtual())
-          PBase = PBT;
-        else 
-          break;
-      }
-      ContainingType = 
-        getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
-    }
-    else if (CXXDecl->isDynamicClass()) 
-      ContainingType = FwdDecl;
-
-    // FIXME: This could be a struct type giving a default visibility different
-    // than C++ class type, but needs llvm metadata changes first.
-    RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
-                                        Size, Align, 0, 0, llvm::DIType(),
-                                        Elements, ContainingType,
-                                        TParamsArray);
+    MN->replaceOperandWith(10, Elements);
+    MN->replaceOperandWith(13, TParamsArray);
   } else
-    RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
-                                         Size, Align, 0, Elements);
+    MN->replaceOperandWith(10, Elements);
 
-  // Now that we have a real decl for the struct, replace anything using the
-  // old decl with the new one.  This will recursively update the debug info.
-  llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
-  RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
-  return llvm::DIType(RealDecl);
+  RegionMap[Ty->getDecl()] = llvm::WeakVH(MN);
+  return llvm::DIType(MN);
 }
 
 /// CreateType - get objective-c object type.
@@ -1274,22 +1235,28 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
   }
   ID = Def;
 
-  // To handle a recursive interface, we first generate a debug descriptor
-  // for the struct as a forward declaration. Then (if it is a definition)
-  // we go through and get debug info for all of its members.  Finally, we
-  // create a descriptor for the complete type (which may refer to the
-  // forward decl if the struct is recursive) and replace all uses of the
-  // forward declaration with the final definition.
-  llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
+  // Bit size, align and offset of the type.
+  uint64_t Size = CGM.getContext().getTypeSize(Ty);
+  uint64_t Align = CGM.getContext().getTypeAlign(Ty);
 
-  llvm::MDNode *MN = FwdDecl;
-  llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
+  unsigned Flags = 0;
+  if (ID->getImplementation())
+    Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
+
+  llvm::DIType RealDecl =
+    DBuilder.createStructType(Unit, ID->getName(), DefUnit,
+                              Line, Size, Align, Flags,
+                              llvm::DIArray(), RuntimeLang);
+  
   // Otherwise, insert it into the TypeCache so that recursive uses will find
   // it.
-  TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+  TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
   // Push the struct on region stack.
+  llvm::MDNode *MN = RealDecl;
+  llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
+
   LexicalBlockStack.push_back(FwdDeclNode);
-  RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+  RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
 
   // Convert all the elements.
   SmallVector<llvm::Value *, 16> EltTys;
@@ -1302,7 +1269,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
       return llvm::DIType();
     
     llvm::DIType InhTag =
-      DBuilder.createInheritance(FwdDecl, SClassTy, 0, 0);
+      DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
     EltTys.push_back(InhTag);
   }
 
@@ -1381,31 +1348,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
   }
 
   llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
+  RealDecl->replaceOperandWith(10, Elements);
+  
   LexicalBlockStack.pop_back();
-  llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI = 
-    RegionMap.find(Ty->getDecl());
-  if (RI != RegionMap.end())
-    RegionMap.erase(RI);
-
-  // Bit size, align and offset of the type.
-  uint64_t Size = CGM.getContext().getTypeSize(Ty);
-  uint64_t Align = CGM.getContext().getTypeAlign(Ty);
-
-  unsigned Flags = 0;
-  if (ID->getImplementation())
-    Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
-
-  llvm::DIType RealDecl =
-    DBuilder.createStructType(Unit, ID->getName(), DefUnit,
-                                  Line, Size, Align, Flags,
-                                  Elements, RuntimeLang);
-
-  // Now that we have a real decl for the struct, replace anything using the
-  // old decl with the new one.  This will recursively update the debug info.
-  llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
-  RegionMap[ID] = llvm::WeakVH(RealDecl);
-
   return RealDecl;
 }
 
@@ -1637,6 +1582,26 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
   return llvm::DIType();
 }
 
+/// getCompletedTypeOrNull - Get the type from the cache or return null if it
+/// doesn't exist.
+llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
+
+  // Unwrap the type as needed for debug information.
+  Ty = UnwrapTypeForDebugInfo(Ty);
+
+  // Check for existing entry.
+  llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+    CompletedTypeCache.find(Ty.getAsOpaquePtr());
+  if (it != CompletedTypeCache.end()) {
+    // Verify that the debug info still exists.
+    if (&*it->second)
+      return llvm::DIType(cast<llvm::MDNode>(it->second));
+  }
+
+  return llvm::DIType();
+}
+
+
 /// getOrCreateType - Get the type from the cache or create a new
 /// one if necessary.
 llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
@@ -1646,14 +1611,18 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
   // Unwrap the type as needed for debug information.
   Ty = UnwrapTypeForDebugInfo(Ty);
   
-  llvm::DIType T = getTypeOrNull(Ty);
+  llvm::DIType T = getCompletedTypeOrNull(Ty);
+
   if (T.Verify()) return T;
 
   // Otherwise create the type.
   llvm::DIType Res = CreateTypeNode(Ty, Unit);
-
+  
   // And update the type cache.
-  TypeCache[Ty.getAsOpaquePtr()] = Res;  
+  TypeCache[Ty.getAsOpaquePtr()] = Res;
+
+  if (!Res.isForwardDecl())
+    CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
   return Res;
 }
 
@@ -1737,6 +1706,123 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
   return llvm::DIType();
 }
 
+/// getOrCreateLimitedType - Get the type from the cache or create a new
+/// limited type if necessary.
+llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
+                                                llvm::DIFile Unit) {
+  if (Ty.isNull())
+    return llvm::DIType();
+
+  // Unwrap the type as needed for debug information.
+  Ty = UnwrapTypeForDebugInfo(Ty);
+
+  llvm::DIType T = getTypeOrNull(Ty);
+
+  // We may have cached a forward decl when we could have created
+  // a non-forward decl. Go ahead and create a non-forward decl
+  // now.
+  if (T.Verify() && !T.isForwardDecl()) return T;
+
+  // Otherwise create the type.
+  llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit);
+
+  // And update the type cache.
+  TypeCache[Ty.getAsOpaquePtr()] = Res;
+  return Res;
+}
+
+// TODO: Currently used for context chains when limiting debug info.
+llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
+  RecordDecl *RD = Ty->getDecl();
+  
+  // Get overall information about the record type for the debug info.
+  llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+  unsigned Line = getLineNumber(RD->getLocation());
+  StringRef RDName = RD->getName();
+
+  llvm::DIDescriptor RDContext;
+  if (CGM.getCodeGenOpts().LimitDebugInfo)
+    RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
+  else
+    RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+
+  // If this is just a forward declaration, construct an appropriately
+  // marked node and just return it.
+  if (!RD->getDefinition()) {
+    llvm::DIType RTy = createRecordFwdDecl(RD, RDContext);
+    TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RTy;
+    return RTy;
+  }
+
+  uint64_t Size = CGM.getContext().getTypeSize(Ty);
+  uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+  const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+  llvm::MDNode *RealDecl = NULL;
+  
+  if (RD->isUnion())
+    RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
+                                       Size, Align, 0, llvm::DIArray());
+  else if (CXXDecl) {
+    RDName = getClassName(RD);
+    
+    // FIXME: This could be a struct type giving a default visibility different
+    // than C++ class type, but needs llvm metadata changes first.
+    RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
+                                       Size, Align, 0, 0, llvm::DIType(),
+                                       llvm::DIArray(), NULL,
+                                       llvm::DIArray());
+  } else
+    RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
+                                        Size, Align, 0, llvm::DIArray());
+
+  RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
+  TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl);
+
+  if (CXXDecl) {
+    // A class's primary base or the class itself contains the vtable.
+    llvm::MDNode *ContainingType = NULL;
+    const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+    if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
+      // Seek non virtual primary base root.
+      while (1) {
+       const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
+       const CXXRecordDecl *PBT = BRL.getPrimaryBase();
+       if (PBT && !BRL.isPrimaryBaseVirtual())
+         PBase = PBT;
+       else
+         break;
+      }
+      ContainingType =
+       getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
+    }
+    else if (CXXDecl->isDynamicClass())
+      ContainingType = RealDecl;
+
+    RealDecl->replaceOperandWith(9, ContainingType);
+  }
+  return llvm::DIType(RealDecl);
+}
+
+/// CreateLimitedTypeNode - Create a new debug type node, but only forward
+/// declare composite types that haven't been processed yet.
+llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) {
+
+  // Work out details of type.
+  switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+        #include "clang/AST/TypeNodes.def"
+    llvm_unreachable("Dependent types cannot show up in debug information");
+
+  case Type::Record:
+    return CreateLimitedType(cast<RecordType>(Ty));
+  default:
+    return CreateTypeNode(Ty, Unit);
+  }
+}
+
 /// CreateMemberType - Create new member and increase Offset by FType's size.
 llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
                                            StringRef Name,
index 48cf3fa19e6b297efde7ceba2f8484db14db60b3..640026673b38d4906bb62e5ca23b62a1bcec4779 100644 (file)
@@ -53,6 +53,9 @@ class CGDebugInfo {
   /// TypeCache - Cache of previously constructed Types.
   llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
 
+  /// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
+  llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
+
   bool BlockLiteralGenericSet;
   llvm::DIType BlockLiteralGeneric;
 
@@ -84,6 +87,7 @@ class CGDebugInfo {
   llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F);
   llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
   llvm::DIType CreateType(const RecordType *Ty);
+  llvm::DIType CreateLimitedType(const RecordType *Ty);
   llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
   llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
   llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
@@ -94,6 +98,7 @@ class CGDebugInfo {
   llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
   llvm::DIType CreateEnumType(const EnumDecl *ED);
   llvm::DIType getTypeOrNull(const QualType);
+  llvm::DIType getCompletedTypeOrNull(const QualType);
   llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
                                      llvm::DIFile F);
   llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
@@ -257,9 +262,17 @@ private:
   /// necessary.
   llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F);
 
+  /// getOrCreateLimitedType - Get the type from the cache or create a new
+  /// partial type if necessary.
+  llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F);
+
   /// CreateTypeNode - Create type metadata for a source language type.
   llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
 
+  /// CreateLimitedTypeNode - Create type metadata for a source language
+  /// type, but only partial types for records.
+  llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
+
   /// CreateMemberType - Create new member and increase Offset by FType's size.
   llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
                                 StringRef Name, uint64_t *Offset);
index 695d1b0967ed9ded5c1683471abd977c2342c3dc..1f50256dff7eefe713171fc4db7f4bb6f5555d1b 100644 (file)
@@ -19,6 +19,6 @@ protected:
 
 Test t;
 
-// CHECK: metadata !"data", metadata !7, i32 13, i64 32, i64 32, i32 0, i32 0
+// CHECK: metadata !"data", metadata !7, i32 14, i64 32, i64 32, i32 0, i32 0
 // CHECK: metadata !"", null, i32 0, i64 64, i64 64, i64 0, i32 0, metadata !5} ; [ DW_TAG_pointer_type ]
 // CHECK-NOT: metadata !"data", metadata !7, i32 13, i64 0, i64 0, i32 0, i32 4,