[cfe-commits] r150752 - in /cfe/trunk: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h test/CodeGenCXX/debug-info-dup-fwd-decl.cpp

Chad Rosier mcrosier at apple.com
Thu Feb 16 16:19:24 PST 2012


*begins thinking of very _mean_ words to say to Eric if and when the compile-time regressions come*  ;)

 Chad

On Feb 16, 2012, at 2:54 PM, Eric Christopher wrote:

> Author: echristo
> Date: Thu Feb 16 16:54:45 2012
> New Revision: 150752
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=150752&view=rev
> Log:
> Reapply r150631:
> 
>    "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.
> 
> Modified:
>    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
>    cfe/trunk/lib/CodeGen/CGDebugInfo.h
>    cfe/trunk/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
> 
> Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=150752&r1=150751&r2=150752&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Thu Feb 16 16:54:45 2012
> @@ -524,11 +524,8 @@
> 
>   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 @@
>     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 @@
>   // 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 @@
> 
>   // 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 @@
>   // 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 @@
>   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 @@
>   }
>   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 @@
>       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::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 @@
>   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 @@
>   // 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 @@
>   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,
> 
> Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=150752&r1=150751&r2=150752&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original)
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Thu Feb 16 16:54:45 2012
> @@ -53,6 +53,9 @@
>   /// 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 @@
>   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 @@
>   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 @@
>   /// 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);
> 
> Modified: cfe/trunk/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp?rev=150752&r1=150751&r2=150752&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp Thu Feb 16 16:54:45 2012
> @@ -19,6 +19,6 @@
> 
> 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,
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list