+namespace {
+struct FieldSeparator {
+ bool Skip;
+ const char *Sep;
+ FieldSeparator(const char *Sep = ", ") : Skip(true), Sep(Sep) {}
+};
+raw_ostream &operator<<(raw_ostream &OS, FieldSeparator &FS) {
+ if (FS.Skip) {
+ FS.Skip = false;
+ return OS;
+ }
+ return OS << FS.Sep;
+}
+struct MDFieldPrinter {
+ raw_ostream &Out;
+ FieldSeparator FS;
+ TypePrinting *TypePrinter;
+ SlotTracker *Machine;
+ const Module *Context;
+
+ explicit MDFieldPrinter(raw_ostream &Out)
+ : Out(Out), TypePrinter(nullptr), Machine(nullptr), Context(nullptr) {}
+ MDFieldPrinter(raw_ostream &Out, TypePrinting *TypePrinter,
+ SlotTracker *Machine, const Module *Context)
+ : Out(Out), TypePrinter(TypePrinter), Machine(Machine), Context(Context) {
+ }
+ void printTag(const DINode *N);
+ void printString(StringRef Name, StringRef Value,
+ bool ShouldSkipEmpty = true);
+ void printMetadata(StringRef Name, const Metadata *MD,
+ bool ShouldSkipNull = true);
+ template <class IntTy>
+ void printInt(StringRef Name, IntTy Int, bool ShouldSkipZero = true);
+ void printBool(StringRef Name, bool Value);
+ void printDIFlags(StringRef Name, unsigned Flags);
+ template <class IntTy, class Stringifier>
+ void printDwarfEnum(StringRef Name, IntTy Value, Stringifier toString,
+ bool ShouldSkipZero = true);
+};
+} // end namespace
+
+void MDFieldPrinter::printTag(const DINode *N) {
+ Out << FS << "tag: ";
+ if (const char *Tag = dwarf::TagString(N->getTag()))
+ Out << Tag;
+ else
+ Out << N->getTag();
+}
+
+void MDFieldPrinter::printString(StringRef Name, StringRef Value,
+ bool ShouldSkipEmpty) {
+ if (ShouldSkipEmpty && Value.empty())
+ return;
+
+ Out << FS << Name << ": \"";
+ PrintEscapedString(Value, Out);
+ Out << "\"";
+}
+
+static void writeMetadataAsOperand(raw_ostream &Out, const Metadata *MD,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine,
+ const Module *Context) {
+ if (!MD) {
+ Out << "null";
+ return;
+ }
+ WriteAsOperandInternal(Out, MD, TypePrinter, Machine, Context);
+}
+
+void MDFieldPrinter::printMetadata(StringRef Name, const Metadata *MD,
+ bool ShouldSkipNull) {
+ if (ShouldSkipNull && !MD)
+ return;
+
+ Out << FS << Name << ": ";
+ writeMetadataAsOperand(Out, MD, TypePrinter, Machine, Context);
+}
+
+template <class IntTy>
+void MDFieldPrinter::printInt(StringRef Name, IntTy Int, bool ShouldSkipZero) {
+ if (ShouldSkipZero && !Int)
+ return;
+
+ Out << FS << Name << ": " << Int;
+}
+
+void MDFieldPrinter::printBool(StringRef Name, bool Value) {
+ Out << FS << Name << ": " << (Value ? "true" : "false");
+}
+
+void MDFieldPrinter::printDIFlags(StringRef Name, unsigned Flags) {
+ if (!Flags)
+ return;
+
+ Out << FS << Name << ": ";
+
+ SmallVector<unsigned, 8> SplitFlags;
+ unsigned Extra = DINode::splitFlags(Flags, SplitFlags);
+
+ FieldSeparator FlagsFS(" | ");
+ for (unsigned F : SplitFlags) {
+ const char *StringF = DINode::getFlagString(F);
+ assert(StringF && "Expected valid flag");
+ Out << FlagsFS << StringF;
+ }
+ if (Extra || SplitFlags.empty())
+ Out << FlagsFS << Extra;
+}
+
+template <class IntTy, class Stringifier>
+void MDFieldPrinter::printDwarfEnum(StringRef Name, IntTy Value,
+ Stringifier toString, bool ShouldSkipZero) {
+ if (!Value)
+ return;
+
+ Out << FS << Name << ": ";
+ if (const char *S = toString(Value))
+ Out << S;
+ else
+ Out << Value;
+}
+
+static void writeGenericDINode(raw_ostream &Out, const GenericDINode *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!GenericDINode(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printTag(N);
+ Printer.printString("header", N->getHeader());
+ if (N->getNumDwarfOperands()) {
+ Out << Printer.FS << "operands: {";
+ FieldSeparator IFS;
+ for (auto &I : N->dwarf_operands()) {
+ Out << IFS;
+ writeMetadataAsOperand(Out, I, TypePrinter, Machine, Context);
+ }
+ Out << "}";
+ }
+ Out << ")";
+}
+
+static void writeDILocation(raw_ostream &Out, const DILocation *DL,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DILocation(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ // Always output the line, since 0 is a relevant and important value for it.
+ Printer.printInt("line", DL->getLine(), /* ShouldSkipZero */ false);
+ Printer.printInt("column", DL->getColumn());
+ Printer.printMetadata("scope", DL->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("inlinedAt", DL->getRawInlinedAt());
+ Out << ")";
+}
+
+static void writeDISubrange(raw_ostream &Out, const DISubrange *N,
+ TypePrinting *, SlotTracker *, const Module *) {
+ Out << "!DISubrange(";
+ MDFieldPrinter Printer(Out);
+ Printer.printInt("count", N->getCount(), /* ShouldSkipZero */ false);
+ Printer.printInt("lowerBound", N->getLowerBound());
+ Out << ")";
+}
+
+static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N,
+ TypePrinting *, SlotTracker *, const Module *) {
+ Out << "!DIEnumerator(";
+ MDFieldPrinter Printer(Out);
+ Printer.printString("name", N->getName(), /* ShouldSkipEmpty */ false);
+ Printer.printInt("value", N->getValue(), /* ShouldSkipZero */ false);
+ Out << ")";
+}
+
+static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N,
+ TypePrinting *, SlotTracker *, const Module *) {
+ Out << "!DIBasicType(";
+ MDFieldPrinter Printer(Out);
+ if (N->getTag() != dwarf::DW_TAG_base_type)
+ Printer.printTag(N);
+ Printer.printString("name", N->getName());
+ Printer.printInt("size", N->getSizeInBits());
+ Printer.printInt("align", N->getAlignInBits());
+ Printer.printDwarfEnum("encoding", N->getEncoding(),
+ dwarf::AttributeEncodingString);
+ Out << ")";
+}
+
+static void writeDIDerivedType(raw_ostream &Out, const DIDerivedType *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DIDerivedType(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printTag(N);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("scope", N->getRawScope());
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printMetadata("baseType", N->getRawBaseType(),
+ /* ShouldSkipNull */ false);
+ Printer.printInt("size", N->getSizeInBits());
+ Printer.printInt("align", N->getAlignInBits());
+ Printer.printInt("offset", N->getOffsetInBits());
+ Printer.printDIFlags("flags", N->getFlags());
+ Printer.printMetadata("extraData", N->getRawExtraData());
+ Out << ")";
+}
+
+static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine, const Module *Context) {
+ Out << "!DICompositeType(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printTag(N);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("scope", N->getRawScope());
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printMetadata("baseType", N->getRawBaseType());
+ Printer.printInt("size", N->getSizeInBits());
+ Printer.printInt("align", N->getAlignInBits());
+ Printer.printInt("offset", N->getOffsetInBits());
+ Printer.printDIFlags("flags", N->getFlags());
+ Printer.printMetadata("elements", N->getRawElements());
+ Printer.printDwarfEnum("runtimeLang", N->getRuntimeLang(),
+ dwarf::LanguageString);
+ Printer.printMetadata("vtableHolder", N->getRawVTableHolder());
+ Printer.printMetadata("templateParams", N->getRawTemplateParams());
+ Printer.printString("identifier", N->getIdentifier());
+ Out << ")";
+}
+
+static void writeDISubroutineType(raw_ostream &Out, const DISubroutineType *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine, const Module *Context) {
+ Out << "!DISubroutineType(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printDIFlags("flags", N->getFlags());
+ Printer.printMetadata("types", N->getRawTypeArray(),
+ /* ShouldSkipNull */ false);
+ Out << ")";
+}
+
+static void writeDIFile(raw_ostream &Out, const DIFile *N, TypePrinting *,
+ SlotTracker *, const Module *) {
+ Out << "!DIFile(";
+ MDFieldPrinter Printer(Out);
+ Printer.printString("filename", N->getFilename(),
+ /* ShouldSkipEmpty */ false);
+ Printer.printString("directory", N->getDirectory(),
+ /* ShouldSkipEmpty */ false);
+ Out << ")";
+}
+
+static void writeDICompileUnit(raw_ostream &Out, const DICompileUnit *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DICompileUnit(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printDwarfEnum("language", N->getSourceLanguage(),
+ dwarf::LanguageString, /* ShouldSkipZero */ false);
+ Printer.printMetadata("file", N->getRawFile(), /* ShouldSkipNull */ false);
+ Printer.printString("producer", N->getProducer());
+ Printer.printBool("isOptimized", N->isOptimized());
+ Printer.printString("flags", N->getFlags());
+ Printer.printInt("runtimeVersion", N->getRuntimeVersion(),
+ /* ShouldSkipZero */ false);
+ Printer.printString("splitDebugFilename", N->getSplitDebugFilename());
+ Printer.printInt("emissionKind", N->getEmissionKind(),
+ /* ShouldSkipZero */ false);
+ Printer.printMetadata("enums", N->getRawEnumTypes());
+ Printer.printMetadata("retainedTypes", N->getRawRetainedTypes());
+ Printer.printMetadata("subprograms", N->getRawSubprograms());
+ Printer.printMetadata("globals", N->getRawGlobalVariables());
+ Printer.printMetadata("imports", N->getRawImportedEntities());
+ Out << ")";
+}
+
+static void writeDISubprogram(raw_ostream &Out, const DISubprogram *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DISubprogram(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printString("name", N->getName());
+ Printer.printString("linkageName", N->getLinkageName());
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printMetadata("type", N->getRawType());
+ Printer.printBool("isLocal", N->isLocalToUnit());
+ Printer.printBool("isDefinition", N->isDefinition());
+ Printer.printInt("scopeLine", N->getScopeLine());
+ Printer.printMetadata("containingType", N->getRawContainingType());
+ Printer.printDwarfEnum("virtuality", N->getVirtuality(),
+ dwarf::VirtualityString);
+ Printer.printInt("virtualIndex", N->getVirtualIndex());
+ Printer.printDIFlags("flags", N->getFlags());
+ Printer.printBool("isOptimized", N->isOptimized());
+ Printer.printMetadata("function", N->getRawFunction());
+ Printer.printMetadata("templateParams", N->getRawTemplateParams());
+ Printer.printMetadata("declaration", N->getRawDeclaration());
+ Printer.printMetadata("variables", N->getRawVariables());
+ Out << ")";
+}
+
+static void writeDILexicalBlock(raw_ostream &Out, const DILexicalBlock *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DILexicalBlock(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printInt("column", N->getColumn());
+ Out << ")";
+}
+
+static void writeDILexicalBlockFile(raw_ostream &Out,
+ const DILexicalBlockFile *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DILexicalBlockFile(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("discriminator", N->getDiscriminator(),
+ /* ShouldSkipZero */ false);
+ Out << ")";
+}
+
+static void writeDINamespace(raw_ostream &Out, const DINamespace *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DINamespace(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Out << ")";
+}
+
+static void writeDITemplateTypeParameter(raw_ostream &Out,
+ const DITemplateTypeParameter *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DITemplateTypeParameter(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("type", N->getRawType(), /* ShouldSkipNull */ false);
+ Out << ")";
+}
+
+static void writeDITemplateValueParameter(raw_ostream &Out,
+ const DITemplateValueParameter *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DITemplateValueParameter(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ if (N->getTag() != dwarf::DW_TAG_template_value_parameter)
+ Printer.printTag(N);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("type", N->getRawType());
+ Printer.printMetadata("value", N->getValue(), /* ShouldSkipNull */ false);
+ Out << ")";
+}
+
+static void writeDIGlobalVariable(raw_ostream &Out, const DIGlobalVariable *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine, const Module *Context) {
+ Out << "!DIGlobalVariable(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printString("name", N->getName());
+ Printer.printString("linkageName", N->getLinkageName());
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printMetadata("type", N->getRawType());
+ Printer.printBool("isLocal", N->isLocalToUnit());
+ Printer.printBool("isDefinition", N->isDefinition());
+ Printer.printMetadata("variable", N->getRawVariable());
+ Printer.printMetadata("declaration", N->getRawStaticDataMemberDeclaration());
+ Out << ")";
+}
+
+static void writeDILocalVariable(raw_ostream &Out, const DILocalVariable *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine, const Module *Context) {
+ Out << "!DILocalVariable(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printTag(N);
+ Printer.printString("name", N->getName());
+ Printer.printInt("arg", N->getArg(),
+ /* ShouldSkipZero */
+ N->getTag() == dwarf::DW_TAG_auto_variable);
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printMetadata("type", N->getRawType());
+ Printer.printDIFlags("flags", N->getFlags());
+ Out << ")";
+}
+
+static void writeDIExpression(raw_ostream &Out, const DIExpression *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DIExpression(";
+ FieldSeparator FS;
+ if (N->isValid()) {
+ for (auto I = N->expr_op_begin(), E = N->expr_op_end(); I != E; ++I) {
+ const char *OpStr = dwarf::OperationEncodingString(I->getOp());
+ assert(OpStr && "Expected valid opcode");
+
+ Out << FS << OpStr;
+ for (unsigned A = 0, AE = I->getNumArgs(); A != AE; ++A)
+ Out << FS << I->getArg(A);
+ }
+ } else {
+ for (const auto &I : N->getElements())
+ Out << FS << I;
+ }
+ Out << ")";
+}
+
+static void writeDIObjCProperty(raw_ostream &Out, const DIObjCProperty *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context) {
+ Out << "!DIObjCProperty(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("file", N->getRawFile());
+ Printer.printInt("line", N->getLine());
+ Printer.printString("setter", N->getSetterName());
+ Printer.printString("getter", N->getGetterName());
+ Printer.printInt("attributes", N->getAttributes());
+ Printer.printMetadata("type", N->getRawType());
+ Out << ")";
+}
+
+static void writeDIImportedEntity(raw_ostream &Out, const DIImportedEntity *N,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine, const Module *Context) {
+ Out << "!DIImportedEntity(";
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ Printer.printTag(N);
+ Printer.printString("name", N->getName());
+ Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false);
+ Printer.printMetadata("entity", N->getRawEntity());
+ Printer.printInt("line", N->getLine());
+ Out << ")";
+}
+
+
+static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node,
+ TypePrinting *TypePrinter,
+ SlotTracker *Machine,
+ const Module *Context) {
+ if (Node->isDistinct())
+ Out << "distinct ";
+ else if (Node->isTemporary())
+ Out << "<temporary!> "; // Handle broken code.
+
+ switch (Node->getMetadataID()) {
+ default:
+ llvm_unreachable("Expected uniquable MDNode");
+#define HANDLE_MDNODE_LEAF(CLASS) \
+ case Metadata::CLASS##Kind: \
+ write##CLASS(Out, cast<CLASS>(Node), TypePrinter, Machine, Context); \
+ break;
+#include "llvm/IR/Metadata.def"
+ }
+}
+