case dwarf::DW_TAG_lexical_block:
case dwarf::DW_TAG_subprogram:
case dwarf::DW_TAG_namespace:
+ case dwarf::DW_TAG_file_type:
return true;
default:
break;
}
- return false;
+ return isType();
}
/// isTemplateTypeParameter - Return true if the specified tag is
return !Fld || isa<MDString>(Fld);
}
+/// Check if a value can be a reference to a type.
+static bool isTypeRef(const Value *Val) {
+ return !Val ||
+ (isa<MDString>(Val) && !cast<MDString>(Val)->getString().empty()) ||
+ (isa<MDNode>(Val) && DIType(cast<MDNode>(Val)).isType());
+}
+
+/// Check if a field at position Elt of a MDNode can be a reference to a type.
+static bool fieldIsTypeRef(const MDNode *DbgNode, unsigned Elt) {
+ Value *Fld = getField(DbgNode, Elt);
+ return isTypeRef(Fld);
+}
+
+/// Check if a value can be a ScopeRef.
+static bool isScopeRef(const Value *Val) {
+ return !Val ||
+ (isa<MDString>(Val) && !cast<MDString>(Val)->getString().empty()) ||
+ (isa<MDNode>(Val) && DIScope(cast<MDNode>(Val)).isScope());
+}
+
+/// Check if a field at position Elt of a MDNode can be a ScopeRef.
+static bool fieldIsScopeRef(const MDNode *DbgNode, unsigned Elt) {
+ Value *Fld = getField(DbgNode, Elt);
+ return isScopeRef(Fld);
+}
+
/// Verify - Verify that a type descriptor is well formed.
bool DIType::Verify() const {
if (!isType())
return false;
// Make sure Context @ field 2 is MDNode.
- if (!fieldIsMDNode(DbgNode, 2))
+ if (!fieldIsScopeRef(DbgNode, 2))
return false;
// FIXME: Sink this into the various subclass verifies.
if (!fieldIsMDNode(DbgNode, 9))
return false;
if (getTag() == dwarf::DW_TAG_ptr_to_member_type)
- // Make sure ClassType @ field 10 is MDNode.
- if (!fieldIsMDNode(DbgNode, 10))
+ // Make sure ClassType @ field 10 is a TypeRef.
+ if (!fieldIsTypeRef(DbgNode, 10))
return false;
return isDerivedType() && DbgNode->getNumOperands() >= 10 &&
// Make sure DerivedFrom @ field 9 and ContainingType @ field 12 are MDNodes.
if (!fieldIsMDNode(DbgNode, 9))
return false;
- if (!fieldIsMDNode(DbgNode, 12))
+ if (!fieldIsTypeRef(DbgNode, 12))
return false;
// Make sure the type identifier at field 14 is MDString, it can be null.
if (!fieldIsMDNode(DbgNode, 7))
return false;
// Containing type @ field 12.
- if (!fieldIsMDNode(DbgNode, 12))
+ if (!fieldIsTypeRef(DbgNode, 12))
return false;
return DbgNode->getNumOperands() == 20;
}
return cast_or_null<MDString>(getField(DbgNode, 14));
}
+#ifndef NDEBUG
+static void VerifySubsetOf(const MDNode *LHS, const MDNode *RHS) {
+ for (unsigned i = 0; i != LHS->getNumOperands(); ++i) {
+ // Skip the 'empty' list (that's a single i32 0, rather than truly empty).
+ if (i == 0 && isa<ConstantInt>(LHS->getOperand(i)))
+ continue;
+ const MDNode *E = cast<MDNode>(LHS->getOperand(i));
+ bool found = false;
+ for (unsigned j = 0; !found && j != RHS->getNumOperands(); ++j)
+ found = E == RHS->getOperand(j);
+ assert(found && "Losing a member during member list replacement");
+ }
+}
+#endif
+
/// \brief Set the array of member DITypes.
void DICompositeType::setTypeArray(DIArray Elements, DIArray TParams) {
assert((!TParams || DbgNode->getNumOperands() == 15) &&
"If you're setting the template parameters this should include a slot "
"for that!");
TrackingVH<MDNode> N(*this);
- N->replaceOperandWith(10, Elements);
+ if (Elements) {
+#ifndef NDEBUG
+ // Check that the new list of members contains all the old members as well.
+ if (const MDNode *El = cast_or_null<MDNode>(N->getOperand(10)))
+ VerifySubsetOf(El, Elements);
+#endif
+ N->replaceOperandWith(10, Elements);
+ }
if (TParams)
N->replaceOperandWith(13, TParams);
DbgNode = N;
setTypeArray(DIArray(MDNode::get(DbgNode->getContext(), M)));
}
+/// Generate a reference to this DIType. Uses the type identifier instead
+/// of the actual MDNode if possible, to help type uniquing.
+DIScopeRef DIScope::generateRef() {
+ if (!isCompositeType())
+ return DIScopeRef(*this);
+ DICompositeType DTy(DbgNode);
+ if (!DTy.getIdentifier())
+ return DIScopeRef(*this);
+ return DIScopeRef(DTy.getIdentifier());
+}
+
/// \brief Set the containing type.
void DICompositeType::setContainingType(DICompositeType ContainingType) {
TrackingVH<MDNode> N(*this);
- N->replaceOperandWith(12, ContainingType);
+ N->replaceOperandWith(12, ContainingType.generateRef());
DbgNode = N;
}
// If the current node has a parent scope then return that,
// else return an empty scope.
-DIScope DIScope::getContext() const {
+DIScopeRef DIScope::getContext() const {
if (isType())
return DIType(DbgNode).getContext();
if (isSubprogram())
- return DISubprogram(DbgNode).getContext();
+ return DIScopeRef(DISubprogram(DbgNode).getContext());
if (isLexicalBlock())
- return DILexicalBlock(DbgNode).getContext();
+ return DIScopeRef(DILexicalBlock(DbgNode).getContext());
if (isLexicalBlockFile())
- return DILexicalBlockFile(DbgNode).getContext();
+ return DIScopeRef(DILexicalBlockFile(DbgNode).getContext());
if (isNameSpace())
- return DINameSpace(DbgNode).getContext();
+ return DIScopeRef(DINameSpace(DbgNode).getContext());
assert((isFile() || isCompileUnit()) && "Unhandled type of scope.");
- return DIScope();
+ return DIScopeRef(NULL);
}
StringRef DIScope::getFilename() const {
return DICompositeType();
}
-/// isSubprogramContext - Return true if Context is either a subprogram
-/// or another context nested inside a subprogram.
-bool llvm::isSubprogramContext(const MDNode *Context) {
- if (!Context)
- return false;
- DIDescriptor D(Context);
- if (D.isSubprogram())
- return true;
- if (D.isType())
- return isSubprogramContext(DIType(Context).getContext());
- return false;
+/// Update DITypeIdentifierMap by going through retained types of each CU.
+DITypeIdentifierMap llvm::generateDITypeIdentifierMap(
+ const NamedMDNode *CU_Nodes) {
+ DITypeIdentifierMap Map;
+ for (unsigned CUi = 0, CUe = CU_Nodes->getNumOperands(); CUi != CUe; ++CUi) {
+ DICompileUnit CU(CU_Nodes->getOperand(CUi));
+ DIArray Retain = CU.getRetainedTypes();
+ for (unsigned Ti = 0, Te = Retain.getNumElements(); Ti != Te; ++Ti) {
+ if (!Retain.getElement(Ti).isCompositeType())
+ continue;
+ DICompositeType Ty(Retain.getElement(Ti));
+ if (MDString *TypeId = Ty.getIdentifier()) {
+ // Definition has priority over declaration.
+ // Try to insert (TypeId, Ty) to Map.
+ std::pair<DITypeIdentifierMap::iterator, bool> P =
+ Map.insert(std::make_pair(TypeId, Ty));
+ // If TypeId already exists in Map and this is a definition, replace
+ // whatever we had (declaration or definition) with the definition.
+ if (!P.second && !Ty.isForwardDecl())
+ P.first->second = Ty;
+ }
+ }
+ }
+ return Map;
}
//===----------------------------------------------------------------------===//
TYs.clear();
Scopes.clear();
NodesSeen.clear();
+ TypeIdentifierMap.clear();
}
/// processModule - Process entire module and collect debug info.
void DebugInfoFinder::processModule(const Module &M) {
if (NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu")) {
+ TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes);
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
DICompileUnit CU(CU_Nodes->getOperand(i));
addCompileUnit(CU);
void DebugInfoFinder::processType(DIType DT) {
if (!addType(DT))
return;
- processScope(DT.getContext());
+ processScope(DT.getContext().resolve(TypeIdentifierMap));
if (DT.isCompositeType()) {
DICompositeType DCT(DT);
processType(DCT.getTypeDerivedFrom());
}
}
}
+
+/// Specialize constructor to make sure it has the correct type.
+template <>
+DIRef<DIScope>::DIRef(const Value *V) : Val(V) {
+ assert(isScopeRef(V) && "DIScopeRef should be a MDString or MDNode");
+}
+template <>
+DIRef<DIType>::DIRef(const Value *V) : Val(V) {
+ assert(isTypeRef(V) && "DITypeRef should be a MDString or MDNode");
+}
+
+/// Specialize getFieldAs to handle fields that are references to DIScopes.
+template <>
+DIScopeRef DIDescriptor::getFieldAs<DIScopeRef>(unsigned Elt) const {
+ return DIScopeRef(getField(DbgNode, Elt));
+}
+/// Specialize getFieldAs to handle fields that are references to DITypes.
+template <>
+DITypeRef DIDescriptor::getFieldAs<DITypeRef>(unsigned Elt) const {
+ return DITypeRef(getField(DbgNode, Elt));
+}
+
+DIScopeRef DIType::getContext() const {
+ return getFieldAs<DIScopeRef>(2);
+}