diff options
Diffstat (limited to 'contrib/llvm/lib/IR/AsmWriter.cpp')
-rw-r--r-- | contrib/llvm/lib/IR/AsmWriter.cpp | 835 |
1 files changed, 707 insertions, 128 deletions
diff --git a/contrib/llvm/lib/IR/AsmWriter.cpp b/contrib/llvm/lib/IR/AsmWriter.cpp index 0fafe82404e4..99a25a723b4a 100644 --- a/contrib/llvm/lib/IR/AsmWriter.cpp +++ b/contrib/llvm/lib/IR/AsmWriter.cpp @@ -7,7 +7,9 @@ // //===----------------------------------------------------------------------===// // -// This library implements the functionality defined in llvm/IR/Writer.h +// This library implements `print` family of functions in classes like +// Module, Function, Value, etc. In-memory representation of those classes is +// converted to IR strings. // // Note that these routines must be extremely tolerant of various errors in the // LLVM code, because it can be used for debugging transformations. @@ -28,6 +30,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Config/llvm-config.h" #include "llvm/IR/Argument.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/Attributes.h" @@ -56,6 +59,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSlotTracker.h" +#include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Statepoint.h" #include "llvm/IR/Type.h" @@ -195,7 +199,7 @@ static void predictValueUseListOrderImpl(const Value *V, const Function *F, !isa<GlobalVariable>(V) && !isa<Function>(V) && !isa<BasicBlock>(V); if (auto *BA = dyn_cast<BlockAddress>(V)) ID = OM.lookup(BA->getBasicBlock()).first; - std::sort(List.begin(), List.end(), [&](const Entry &L, const Entry &R) { + llvm::sort(List.begin(), List.end(), [&](const Entry &L, const Entry &R) { const Use *LU = L.first; const Use *RU = R.first; if (LU == RU) @@ -383,16 +387,6 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { } } -void llvm::PrintEscapedString(StringRef Name, raw_ostream &Out) { - for (unsigned i = 0, e = Name.size(); i != e; ++i) { - unsigned char C = Name[i]; - if (isprint(C) && C != '\\' && C != '"') - Out << C; - else - Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F); - } -} - enum PrefixType { GlobalPrefix, ComdatPrefix, @@ -430,7 +424,7 @@ void llvm::printLLVMNameWithoutPrefix(raw_ostream &OS, StringRef Name) { // Okay, we need quotes. Output the quotes and escape any scary characters as // needed. OS << '"'; - PrintEscapedString(Name, OS); + printEscapedString(Name, OS); OS << '"'; } @@ -468,27 +462,73 @@ namespace { class TypePrinting { public: - /// NamedTypes - The named types that are used by the current module. - TypeFinder NamedTypes; - - /// NumberedTypes - The numbered types, along with their value. - DenseMap<StructType*, unsigned> NumberedTypes; + TypePrinting(const Module *M = nullptr) : DeferredM(M) {} - TypePrinting() = default; TypePrinting(const TypePrinting &) = delete; TypePrinting &operator=(const TypePrinting &) = delete; - void incorporateTypes(const Module &M); + /// The named types that are used by the current module. + TypeFinder &getNamedTypes(); + + /// The numbered types, number to type mapping. + std::vector<StructType *> &getNumberedTypes(); + + bool empty(); void print(Type *Ty, raw_ostream &OS); void printStructBody(StructType *Ty, raw_ostream &OS); + +private: + void incorporateTypes(); + + /// A module to process lazily when needed. Set to nullptr as soon as used. + const Module *DeferredM; + + TypeFinder NamedTypes; + + // The numbered types, along with their value. + DenseMap<StructType *, unsigned> Type2Number; + + std::vector<StructType *> NumberedTypes; }; } // end anonymous namespace -void TypePrinting::incorporateTypes(const Module &M) { - NamedTypes.run(M, false); +TypeFinder &TypePrinting::getNamedTypes() { + incorporateTypes(); + return NamedTypes; +} + +std::vector<StructType *> &TypePrinting::getNumberedTypes() { + incorporateTypes(); + + // We know all the numbers that each type is used and we know that it is a + // dense assignment. Convert the map to an index table, if it's not done + // already (judging from the sizes): + if (NumberedTypes.size() == Type2Number.size()) + return NumberedTypes; + + NumberedTypes.resize(Type2Number.size()); + for (const auto &P : Type2Number) { + assert(P.second < NumberedTypes.size() && "Didn't get a dense numbering?"); + assert(!NumberedTypes[P.second] && "Didn't get a unique numbering?"); + NumberedTypes[P.second] = P.first; + } + return NumberedTypes; +} + +bool TypePrinting::empty() { + incorporateTypes(); + return NamedTypes.empty() && Type2Number.empty(); +} + +void TypePrinting::incorporateTypes() { + if (!DeferredM) + return; + + NamedTypes.run(*DeferredM, false); + DeferredM = nullptr; // The list of struct types we got back includes all the struct types, split // the unnamed ones out to a numbering and remove the anonymous structs. @@ -503,7 +543,7 @@ void TypePrinting::incorporateTypes(const Module &M) { continue; if (STy->getName().empty()) - NumberedTypes[STy] = NextNumber++; + Type2Number[STy] = NextNumber++; else *NextToUse++ = STy; } @@ -511,9 +551,8 @@ void TypePrinting::incorporateTypes(const Module &M) { NamedTypes.erase(NextToUse, NamedTypes.end()); } - -/// CalcTypeName - Write the specified type to the specified raw_ostream, making -/// use of type names or up references to shorten the type name where possible. +/// Write the specified type to the specified raw_ostream, making use of type +/// names or up references to shorten the type name where possible. void TypePrinting::print(Type *Ty, raw_ostream &OS) { switch (Ty->getTypeID()) { case Type::VoidTyID: OS << "void"; return; @@ -557,8 +596,9 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) { if (!STy->getName().empty()) return PrintLLVMName(OS, STy->getName(), LocalPrefix); - DenseMap<StructType*, unsigned>::iterator I = NumberedTypes.find(STy); - if (I != NumberedTypes.end()) + incorporateTypes(); + const auto I = Type2Number.find(STy); + if (I != Type2Number.end()) OS << '%' << I->second; else // Not enumerated, print the hex address. OS << "%\"type " << STy << '\"'; @@ -637,6 +677,9 @@ private: bool FunctionProcessed = false; bool ShouldInitializeAllMetadata; + /// The summary index for which we are holding slot numbers. + const ModuleSummaryIndex *TheIndex = nullptr; + /// mMap - The slot map for the module level data. ValueMap mMap; unsigned mNext = 0; @@ -653,6 +696,14 @@ private: DenseMap<AttributeSet, unsigned> asMap; unsigned asNext = 0; + /// ModulePathMap - The slot map for Module paths used in the summary index. + StringMap<unsigned> ModulePathMap; + unsigned ModulePathNext = 0; + + /// GUIDMap - The slot map for GUIDs used in the summary index. + DenseMap<GlobalValue::GUID, unsigned> GUIDMap; + unsigned GUIDNext = 0; + public: /// Construct from a module. /// @@ -670,6 +721,9 @@ public: explicit SlotTracker(const Function *F, bool ShouldInitializeAllMetadata = false); + /// Construct from a module summary index. + explicit SlotTracker(const ModuleSummaryIndex *Index); + SlotTracker(const SlotTracker &) = delete; SlotTracker &operator=(const SlotTracker &) = delete; @@ -679,6 +733,8 @@ public: int getGlobalSlot(const GlobalValue *V); int getMetadataSlot(const MDNode *N); int getAttributeGroupSlot(AttributeSet AS); + int getModulePathSlot(StringRef Path); + int getGUIDSlot(GlobalValue::GUID GUID); /// If you'd like to deal with a function instead of just a module, use /// this method to get its data into the SlotTracker. @@ -710,8 +766,12 @@ public: unsigned as_size() const { return asMap.size(); } bool as_empty() const { return asMap.empty(); } - /// This function does the actual initialization. - inline void initialize(); + /// GUID map iterators. + using guid_iterator = DenseMap<GlobalValue::GUID, unsigned>::iterator; + + /// These functions do the actual initialization. + inline void initializeIfNeeded(); + void initializeIndexIfNeeded(); // Implementation Details private: @@ -724,12 +784,16 @@ private: /// CreateFunctionSlot - Insert the specified Value* into the slot table. void CreateFunctionSlot(const Value *V); - /// \brief Insert the specified AttributeSet into the slot table. + /// Insert the specified AttributeSet into the slot table. void CreateAttributeSetSlot(AttributeSet AS); + inline void CreateModulePathSlot(StringRef Path); + void CreateGUIDSlot(GlobalValue::GUID GUID); + /// Add all of the module level global variables (and their initializers) /// and function declarations, but not the contents of those functions. void processModule(); + void processIndex(); /// Add all of the functions arguments, basic blocks, and instructions. void processFunction(); @@ -830,7 +894,10 @@ SlotTracker::SlotTracker(const Function *F, bool ShouldInitializeAllMetadata) : TheModule(F ? F->getParent() : nullptr), TheFunction(F), ShouldInitializeAllMetadata(ShouldInitializeAllMetadata) {} -inline void SlotTracker::initialize() { +SlotTracker::SlotTracker(const ModuleSummaryIndex *Index) + : TheModule(nullptr), ShouldInitializeAllMetadata(false), TheIndex(Index) {} + +inline void SlotTracker::initializeIfNeeded() { if (TheModule) { processModule(); TheModule = nullptr; ///< Prevent re-processing next time we're called. @@ -840,6 +907,13 @@ inline void SlotTracker::initialize() { processFunction(); } +void SlotTracker::initializeIndexIfNeeded() { + if (!TheIndex) + return; + processIndex(); + TheIndex = nullptr; ///< Prevent re-processing next time we're called. +} + // Iterate through all the global variables, functions, and global // variable initializers and create slots for them. void SlotTracker::processModule() { @@ -931,6 +1005,32 @@ void SlotTracker::processFunction() { ST_DEBUG("end processFunction!\n"); } +// Iterate through all the GUID in the index and create slots for them. +void SlotTracker::processIndex() { + ST_DEBUG("begin processIndex!\n"); + assert(TheIndex); + + // The first block of slots are just the module ids, which start at 0 and are + // assigned consecutively. Since the StringMap iteration order isn't + // guaranteed, use a std::map to order by module ID before assigning slots. + std::map<uint64_t, StringRef> ModuleIdToPathMap; + for (auto &ModPath : TheIndex->modulePaths()) + ModuleIdToPathMap[ModPath.second.first] = ModPath.first(); + for (auto &ModPair : ModuleIdToPathMap) + CreateModulePathSlot(ModPair.second); + + // Start numbering the GUIDs after the module ids. + GUIDNext = ModulePathNext; + + for (auto &GlobalList : *TheIndex) + CreateGUIDSlot(GlobalList.first); + + for (auto &TId : TheIndex->typeIds()) + CreateGUIDSlot(GlobalValue::getGUID(TId.first)); + + ST_DEBUG("end processIndex!\n"); +} + void SlotTracker::processGlobalObjectMetadata(const GlobalObject &GO) { SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; GO.getAllMetadata(MDs); @@ -977,7 +1077,7 @@ void SlotTracker::purgeFunction() { /// getGlobalSlot - Get the slot number of a global value. int SlotTracker::getGlobalSlot(const GlobalValue *V) { // Check for uninitialized state and do lazy initialization. - initialize(); + initializeIfNeeded(); // Find the value in the module map ValueMap::iterator MI = mMap.find(V); @@ -987,7 +1087,7 @@ int SlotTracker::getGlobalSlot(const GlobalValue *V) { /// getMetadataSlot - Get the slot number of a MDNode. int SlotTracker::getMetadataSlot(const MDNode *N) { // Check for uninitialized state and do lazy initialization. - initialize(); + initializeIfNeeded(); // Find the MDNode in the module map mdn_iterator MI = mdnMap.find(N); @@ -999,7 +1099,7 @@ int SlotTracker::getLocalSlot(const Value *V) { assert(!isa<Constant>(V) && "Can't get a constant or global slot with this!"); // Check for uninitialized state and do lazy initialization. - initialize(); + initializeIfNeeded(); ValueMap::iterator FI = fMap.find(V); return FI == fMap.end() ? -1 : (int)FI->second; @@ -1007,13 +1107,31 @@ int SlotTracker::getLocalSlot(const Value *V) { int SlotTracker::getAttributeGroupSlot(AttributeSet AS) { // Check for uninitialized state and do lazy initialization. - initialize(); + initializeIfNeeded(); // Find the AttributeSet in the module map. as_iterator AI = asMap.find(AS); return AI == asMap.end() ? -1 : (int)AI->second; } +int SlotTracker::getModulePathSlot(StringRef Path) { + // Check for uninitialized state and do lazy initialization. + initializeIndexIfNeeded(); + + // Find the Module path in the map + auto I = ModulePathMap.find(Path); + return I == ModulePathMap.end() ? -1 : (int)I->second; +} + +int SlotTracker::getGUIDSlot(GlobalValue::GUID GUID) { + // Check for uninitialized state and do lazy initialization. + initializeIndexIfNeeded(); + + // Find the GUID in the map + guid_iterator I = GUIDMap.find(GUID); + return I == GUIDMap.end() ? -1 : (int)I->second; +} + /// CreateModuleSlot - Insert the specified GlobalValue* into the slot table. void SlotTracker::CreateModuleSlot(const GlobalValue *V) { assert(V && "Can't insert a null Value into SlotTracker!"); @@ -1074,6 +1192,16 @@ void SlotTracker::CreateAttributeSetSlot(AttributeSet AS) { asMap[AS] = DestSlot; } +/// Create a new slot for the specified Module +void SlotTracker::CreateModulePathSlot(StringRef Path) { + ModulePathMap[Path] = ModulePathNext++; +} + +/// Create a new slot for the specified GUID +void SlotTracker::CreateGUIDSlot(GlobalValue::GUID GUID) { + GUIDMap[GUID] = GUIDNext++; +} + //===----------------------------------------------------------------------===// // AsmWriter Implementation //===----------------------------------------------------------------------===// @@ -1277,7 +1405,7 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, // i8 with ConstantInt values. if (CA->isString()) { Out << "c\""; - PrintEscapedString(CA->getAsString(), Out); + printEscapedString(CA->getAsString(), Out); Out << '"'; return; } @@ -1463,7 +1591,7 @@ struct MDFieldPrinter { void printTag(const DINode *N); void printMacinfoType(const DIMacroNode *N); - void printChecksumKind(const DIFile *N); + void printChecksum(const DIFile::ChecksumInfo<StringRef> &N); void printString(StringRef Name, StringRef Value, bool ShouldSkipEmpty = true); void printMetadata(StringRef Name, const Metadata *MD, @@ -1498,11 +1626,10 @@ void MDFieldPrinter::printMacinfoType(const DIMacroNode *N) { Out << N->getMacinfoType(); } -void MDFieldPrinter::printChecksumKind(const DIFile *N) { - if (N->getChecksumKind() == DIFile::CSK_None) - // Skip CSK_None checksum kind. - return; - Out << FS << "checksumkind: " << N->getChecksumKindAsString(); +void MDFieldPrinter::printChecksum( + const DIFile::ChecksumInfo<StringRef> &Checksum) { + Out << FS << "checksumkind: " << Checksum.getKindAsString(); + printString("checksum", Checksum.Value, /* ShouldSkipEmpty */ false); } void MDFieldPrinter::printString(StringRef Name, StringRef Value, @@ -1511,7 +1638,7 @@ void MDFieldPrinter::printString(StringRef Name, StringRef Value, return; Out << FS << Name << ": \""; - PrintEscapedString(Value, Out); + printEscapedString(Value, Out); Out << "\""; } @@ -1571,7 +1698,7 @@ void MDFieldPrinter::printDIFlags(StringRef Name, DINode::DIFlags Flags) { void MDFieldPrinter::printEmissionKind(StringRef Name, DICompileUnit::DebugEmissionKind EK) { - Out << FS << Name << ": " << DICompileUnit::EmissionKindString(EK); + Out << FS << Name << ": " << DICompileUnit::emissionKindString(EK); } template <class IntTy, class Stringifier> @@ -1621,10 +1748,15 @@ static void writeDILocation(raw_ostream &Out, const DILocation *DL, } static void writeDISubrange(raw_ostream &Out, const DISubrange *N, - TypePrinting *, SlotTracker *, const Module *) { + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { Out << "!DISubrange("; - MDFieldPrinter Printer(Out); - Printer.printInt("count", N->getCount(), /* ShouldSkipZero */ false); + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + if (auto *CE = N->getCount().dyn_cast<ConstantInt*>()) + Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false); + else + Printer.printMetadata("count", N->getCount().dyn_cast<DIVariable*>(), + /*ShouldSkipNull */ false); Printer.printInt("lowerBound", N->getLowerBound()); Out << ")"; } @@ -1634,7 +1766,13 @@ static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N, Out << "!DIEnumerator("; MDFieldPrinter Printer(Out); Printer.printString("name", N->getName(), /* ShouldSkipEmpty */ false); - Printer.printInt("value", N->getValue(), /* ShouldSkipZero */ false); + if (N->isUnsigned()) { + auto Value = static_cast<uint64_t>(N->getValue()); + Printer.printInt("value", Value, /* ShouldSkipZero */ false); + Printer.printBool("isUnsigned", true); + } else { + Printer.printInt("value", N->getValue(), /* ShouldSkipZero */ false); + } Out << ")"; } @@ -1696,6 +1834,7 @@ static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N, Printer.printMetadata("vtableHolder", N->getRawVTableHolder()); Printer.printMetadata("templateParams", N->getRawTemplateParams()); Printer.printString("identifier", N->getIdentifier()); + Printer.printMetadata("discriminator", N->getRawDiscriminator()); Out << ")"; } @@ -1719,8 +1858,11 @@ static void writeDIFile(raw_ostream &Out, const DIFile *N, TypePrinting *, /* ShouldSkipEmpty */ false); Printer.printString("directory", N->getDirectory(), /* ShouldSkipEmpty */ false); - Printer.printChecksumKind(N); - Printer.printString("checksum", N->getChecksum(), /* ShouldSkipEmpty */ true); + // Print all values for checksum together, or not at all. + if (N->getChecksum()) + Printer.printChecksum(*N->getChecksum()); + Printer.printString("source", N->getSource().getValueOr(StringRef()), + /* ShouldSkipEmpty */ true); Out << ")"; } @@ -1778,7 +1920,7 @@ static void writeDISubprogram(raw_ostream &Out, const DISubprogram *N, Printer.printMetadata("unit", N->getRawUnit()); Printer.printMetadata("templateParams", N->getRawTemplateParams()); Printer.printMetadata("declaration", N->getRawDeclaration()); - Printer.printMetadata("variables", N->getRawVariables()); + Printer.printMetadata("retainedNodes", N->getRawRetainedNodes()); Printer.printMetadata("thrownTypes", N->getRawThrownTypes()); Out << ")"; } @@ -1918,6 +2060,18 @@ static void writeDILocalVariable(raw_ostream &Out, const DILocalVariable *N, Out << ")"; } +static void writeDILabel(raw_ostream &Out, const DILabel *N, + TypePrinting *TypePrinter, + SlotTracker *Machine, const Module *Context) { + Out << "!DILabel("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false); + Printer.printString("name", N->getName()); + Printer.printMetadata("file", N->getRawFile()); + Printer.printInt("line", N->getLine()); + Out << ")"; +} + static void writeDIExpression(raw_ostream &Out, const DIExpression *N, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { @@ -2028,9 +2182,9 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, if (IA->getDialect() == InlineAsm::AD_Intel) Out << "inteldialect "; Out << '"'; - PrintEscapedString(IA->getAsmString(), Out); + printEscapedString(IA->getAsmString(), Out); Out << "\", \""; - PrintEscapedString(IA->getConstraintString(), Out); + printEscapedString(IA->getConstraintString(), Out); Out << '"'; return; } @@ -2109,7 +2263,7 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Metadata *MD, if (const MDString *MDS = dyn_cast<MDString>(MD)) { Out << "!\""; - PrintEscapedString(MDS->getString(), Out); + printEscapedString(MDS->getString(), Out); Out << '"'; return; } @@ -2128,11 +2282,12 @@ namespace { class AssemblyWriter { formatted_raw_ostream &Out; - const Module *TheModule; + const Module *TheModule = nullptr; + const ModuleSummaryIndex *TheIndex = nullptr; std::unique_ptr<SlotTracker> SlotTrackerStorage; SlotTracker &Machine; TypePrinting TypePrinter; - AssemblyAnnotationWriter *AnnotationWriter; + AssemblyAnnotationWriter *AnnotationWriter = nullptr; SetVector<const Comdat *> Comdats; bool IsForDebug; bool ShouldPreserveUseListOrder; @@ -2140,6 +2295,7 @@ class AssemblyWriter { SmallVector<StringRef, 8> MDNames; /// Synchronization scope names registered with LLVMContext. SmallVector<StringRef, 8> SSNs; + DenseMap<const GlobalValueSummary *, GlobalValue::GUID> SummaryToGUIDMap; public: /// Construct an AssemblyWriter with an external SlotTracker @@ -2147,6 +2303,9 @@ public: AssemblyAnnotationWriter *AAW, bool IsForDebug, bool ShouldPreserveUseListOrder = false); + AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, + const ModuleSummaryIndex *Index, bool IsForDebug); + void printMDNodeBody(const MDNode *MD); void printNamedMDNode(const NamedMDNode *NMD); @@ -2182,8 +2341,27 @@ public: void printUseListOrder(const UseListOrder &Order); void printUseLists(const Function *F); + void printModuleSummaryIndex(); + void printSummaryInfo(unsigned Slot, const ValueInfo &VI); + void printSummary(const GlobalValueSummary &Summary); + void printAliasSummary(const AliasSummary *AS); + void printGlobalVarSummary(const GlobalVarSummary *GS); + void printFunctionSummary(const FunctionSummary *FS); + void printTypeIdSummary(const TypeIdSummary &TIS); + void printTypeTestResolution(const TypeTestResolution &TTRes); + void printArgs(const std::vector<uint64_t> &Args); + void printWPDRes(const WholeProgramDevirtResolution &WPDRes); + void printTypeIdInfo(const FunctionSummary::TypeIdInfo &TIDInfo); + void printVFuncId(const FunctionSummary::VFuncId VFId); + void + printNonConstVCalls(const std::vector<FunctionSummary::VFuncId> VCallList, + const char *Tag); + void + printConstVCalls(const std::vector<FunctionSummary::ConstVCall> VCallList, + const char *Tag); + private: - /// \brief Print out metadata attachments. + /// Print out metadata attachments. void printMetadataAttachments( const SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs, StringRef Separator); @@ -2202,17 +2380,21 @@ private: AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M, AssemblyAnnotationWriter *AAW, bool IsForDebug, bool ShouldPreserveUseListOrder) - : Out(o), TheModule(M), Machine(Mac), AnnotationWriter(AAW), + : Out(o), TheModule(M), Machine(Mac), TypePrinter(M), AnnotationWriter(AAW), IsForDebug(IsForDebug), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) { if (!TheModule) return; - TypePrinter.incorporateTypes(*TheModule); for (const GlobalObject &GO : TheModule->global_objects()) if (const Comdat *C = GO.getComdat()) Comdats.insert(C); } +AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, + const ModuleSummaryIndex *Index, bool IsForDebug) + : Out(o), TheIndex(Index), Machine(Mac), TypePrinter(/*Module=*/nullptr), + IsForDebug(IsForDebug), ShouldPreserveUseListOrder(false) {} + void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) { if (!Operand) { Out << "<null operand!>"; @@ -2236,7 +2418,7 @@ void AssemblyWriter::writeSyncScope(const LLVMContext &Context, Context.getSyncScopeNames(SSNs); Out << " syncscope(\""; - PrintEscapedString(SSNs[SSID], Out); + printEscapedString(SSNs[SSID], Out); Out << "\")"; break; } @@ -2297,7 +2479,7 @@ void AssemblyWriter::writeOperandBundles(ImmutableCallSite CS) { FirstBundle = false; Out << '"'; - PrintEscapedString(BU.getTagName(), Out); + printEscapedString(BU.getTagName(), Out); Out << '"'; Out << '('; @@ -2320,7 +2502,7 @@ void AssemblyWriter::writeOperandBundles(ImmutableCallSite CS) { } void AssemblyWriter::printModule(const Module *M) { - Machine.initialize(); + Machine.initializeIfNeeded(); if (ShouldPreserveUseListOrder) UseListOrders = predictUseListOrder(M); @@ -2333,7 +2515,7 @@ void AssemblyWriter::printModule(const Module *M) { if (!M->getSourceFileName().empty()) { Out << "source_filename = \""; - PrintEscapedString(M->getSourceFileName(), Out); + printEscapedString(M->getSourceFileName(), Out); Out << "\"\n"; } @@ -2355,7 +2537,7 @@ void AssemblyWriter::printModule(const Module *M) { // We found a newline, print the portion of the asm string from the // last newline up to this newline. Out << "module asm \""; - PrintEscapedString(Front, Out); + printEscapedString(Front, Out); Out << "\"\n"; } while (!Asm.empty()); } @@ -2414,6 +2596,428 @@ void AssemblyWriter::printModule(const Module *M) { } } +void AssemblyWriter::printModuleSummaryIndex() { + assert(TheIndex); + Machine.initializeIndexIfNeeded(); + + Out << "\n"; + + // Print module path entries. To print in order, add paths to a vector + // indexed by module slot. + std::vector<std::pair<std::string, ModuleHash>> moduleVec; + std::string RegularLTOModuleName = "[Regular LTO]"; + moduleVec.resize(TheIndex->modulePaths().size()); + for (auto &ModPath : TheIndex->modulePaths()) + moduleVec[Machine.getModulePathSlot(ModPath.first())] = std::make_pair( + // A module id of -1 is a special entry for a regular LTO module created + // during the thin link. + ModPath.second.first == -1u ? RegularLTOModuleName + : (std::string)ModPath.first(), + ModPath.second.second); + + unsigned i = 0; + for (auto &ModPair : moduleVec) { + Out << "^" << i++ << " = module: ("; + Out << "path: \""; + printEscapedString(ModPair.first, Out); + Out << "\", hash: ("; + FieldSeparator FS; + for (auto Hash : ModPair.second) + Out << FS << Hash; + Out << "))\n"; + } + + // FIXME: Change AliasSummary to hold a ValueInfo instead of summary pointer + // for aliasee (then update BitcodeWriter.cpp and remove get/setAliaseeGUID). + for (auto &GlobalList : *TheIndex) { + auto GUID = GlobalList.first; + for (auto &Summary : GlobalList.second.SummaryList) + SummaryToGUIDMap[Summary.get()] = GUID; + } + + // Print the global value summary entries. + for (auto &GlobalList : *TheIndex) { + auto GUID = GlobalList.first; + auto VI = TheIndex->getValueInfo(GlobalList); + printSummaryInfo(Machine.getGUIDSlot(GUID), VI); + } + + // Print the TypeIdMap entries. + for (auto &TId : TheIndex->typeIds()) { + auto GUID = GlobalValue::getGUID(TId.first); + Out << "^" << Machine.getGUIDSlot(GUID) << " = typeid: (name: \"" + << TId.first << "\""; + printTypeIdSummary(TId.second); + Out << ") ; guid = " << GUID << "\n"; + } +} + +static const char * +getWholeProgDevirtResKindName(WholeProgramDevirtResolution::Kind K) { + switch (K) { + case WholeProgramDevirtResolution::Indir: + return "indir"; + case WholeProgramDevirtResolution::SingleImpl: + return "singleImpl"; + case WholeProgramDevirtResolution::BranchFunnel: + return "branchFunnel"; + } + llvm_unreachable("invalid WholeProgramDevirtResolution kind"); +} + +static const char *getWholeProgDevirtResByArgKindName( + WholeProgramDevirtResolution::ByArg::Kind K) { + switch (K) { + case WholeProgramDevirtResolution::ByArg::Indir: + return "indir"; + case WholeProgramDevirtResolution::ByArg::UniformRetVal: + return "uniformRetVal"; + case WholeProgramDevirtResolution::ByArg::UniqueRetVal: + return "uniqueRetVal"; + case WholeProgramDevirtResolution::ByArg::VirtualConstProp: + return "virtualConstProp"; + } + llvm_unreachable("invalid WholeProgramDevirtResolution::ByArg kind"); +} + +static const char *getTTResKindName(TypeTestResolution::Kind K) { + switch (K) { + case TypeTestResolution::Unsat: + return "unsat"; + case TypeTestResolution::ByteArray: + return "byteArray"; + case TypeTestResolution::Inline: + return "inline"; + case TypeTestResolution::Single: + return "single"; + case TypeTestResolution::AllOnes: + return "allOnes"; + } + llvm_unreachable("invalid TypeTestResolution kind"); +} + +void AssemblyWriter::printTypeTestResolution(const TypeTestResolution &TTRes) { + Out << "typeTestRes: (kind: " << getTTResKindName(TTRes.TheKind) + << ", sizeM1BitWidth: " << TTRes.SizeM1BitWidth; + + // The following fields are only used if the target does not support the use + // of absolute symbols to store constants. Print only if non-zero. + if (TTRes.AlignLog2) + Out << ", alignLog2: " << TTRes.AlignLog2; + if (TTRes.SizeM1) + Out << ", sizeM1: " << TTRes.SizeM1; + if (TTRes.BitMask) + // BitMask is uint8_t which causes it to print the corresponding char. + Out << ", bitMask: " << (unsigned)TTRes.BitMask; + if (TTRes.InlineBits) + Out << ", inlineBits: " << TTRes.InlineBits; + + Out << ")"; +} + +void AssemblyWriter::printTypeIdSummary(const TypeIdSummary &TIS) { + Out << ", summary: ("; + printTypeTestResolution(TIS.TTRes); + if (!TIS.WPDRes.empty()) { + Out << ", wpdResolutions: ("; + FieldSeparator FS; + for (auto &WPDRes : TIS.WPDRes) { + Out << FS; + Out << "(offset: " << WPDRes.first << ", "; + printWPDRes(WPDRes.second); + Out << ")"; + } + Out << ")"; + } + Out << ")"; +} + +void AssemblyWriter::printArgs(const std::vector<uint64_t> &Args) { + Out << "args: ("; + FieldSeparator FS; + for (auto arg : Args) { + Out << FS; + Out << arg; + } + Out << ")"; +} + +void AssemblyWriter::printWPDRes(const WholeProgramDevirtResolution &WPDRes) { + Out << "wpdRes: (kind: "; + Out << getWholeProgDevirtResKindName(WPDRes.TheKind); + + if (WPDRes.TheKind == WholeProgramDevirtResolution::SingleImpl) + Out << ", singleImplName: \"" << WPDRes.SingleImplName << "\""; + + if (!WPDRes.ResByArg.empty()) { + Out << ", resByArg: ("; + FieldSeparator FS; + for (auto &ResByArg : WPDRes.ResByArg) { + Out << FS; + printArgs(ResByArg.first); + Out << ", byArg: (kind: "; + Out << getWholeProgDevirtResByArgKindName(ResByArg.second.TheKind); + if (ResByArg.second.TheKind == + WholeProgramDevirtResolution::ByArg::UniformRetVal || + ResByArg.second.TheKind == + WholeProgramDevirtResolution::ByArg::UniqueRetVal) + Out << ", info: " << ResByArg.second.Info; + + // The following fields are only used if the target does not support the + // use of absolute symbols to store constants. Print only if non-zero. + if (ResByArg.second.Byte || ResByArg.second.Bit) + Out << ", byte: " << ResByArg.second.Byte + << ", bit: " << ResByArg.second.Bit; + + Out << ")"; + } + Out << ")"; + } + Out << ")"; +} + +static const char *getSummaryKindName(GlobalValueSummary::SummaryKind SK) { + switch (SK) { + case GlobalValueSummary::AliasKind: + return "alias"; + case GlobalValueSummary::FunctionKind: + return "function"; + case GlobalValueSummary::GlobalVarKind: + return "variable"; + } + llvm_unreachable("invalid summary kind"); +} + +void AssemblyWriter::printAliasSummary(const AliasSummary *AS) { + Out << ", aliasee: "; + // The indexes emitted for distributed backends may not include the + // aliasee summary (only if it is being imported directly). Handle + // that case by just emitting "null" as the aliasee. + if (AS->hasAliasee()) + Out << "^" << Machine.getGUIDSlot(SummaryToGUIDMap[&AS->getAliasee()]); + else + Out << "null"; +} + +void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) { + // Nothing for now +} + +static std::string getLinkageName(GlobalValue::LinkageTypes LT) { + switch (LT) { + case GlobalValue::ExternalLinkage: + return "external"; + case GlobalValue::PrivateLinkage: + return "private"; + case GlobalValue::InternalLinkage: + return "internal"; + case GlobalValue::LinkOnceAnyLinkage: + return "linkonce"; + case GlobalValue::LinkOnceODRLinkage: + return "linkonce_odr"; + case GlobalValue::WeakAnyLinkage: + return "weak"; + case GlobalValue::WeakODRLinkage: + return "weak_odr"; + case GlobalValue::CommonLinkage: + return "common"; + case GlobalValue::AppendingLinkage: + return "appending"; + case GlobalValue::ExternalWeakLinkage: + return "extern_weak"; + case GlobalValue::AvailableExternallyLinkage: + return "available_externally"; + } + llvm_unreachable("invalid linkage"); +} + +// When printing the linkage types in IR where the ExternalLinkage is +// not printed, and other linkage types are expected to be printed with +// a space after the name. +static std::string getLinkageNameWithSpace(GlobalValue::LinkageTypes LT) { + if (LT == GlobalValue::ExternalLinkage) + return ""; + return getLinkageName(LT) + " "; +} + +static const char *getHotnessName(CalleeInfo::HotnessType HT) { + switch (HT) { + case CalleeInfo::HotnessType::Unknown: + return "unknown"; + case CalleeInfo::HotnessType::Cold: + return "cold"; + case CalleeInfo::HotnessType::None: + return "none"; + case CalleeInfo::HotnessType::Hot: + return "hot"; + case CalleeInfo::HotnessType::Critical: + return "critical"; + } + llvm_unreachable("invalid hotness"); +} + +void AssemblyWriter::printFunctionSummary(const FunctionSummary *FS) { + Out << ", insts: " << FS->instCount(); + + FunctionSummary::FFlags FFlags = FS->fflags(); + if (FFlags.ReadNone | FFlags.ReadOnly | FFlags.NoRecurse | + FFlags.ReturnDoesNotAlias) { + Out << ", funcFlags: ("; + Out << "readNone: " << FFlags.ReadNone; + Out << ", readOnly: " << FFlags.ReadOnly; + Out << ", noRecurse: " << FFlags.NoRecurse; + Out << ", returnDoesNotAlias: " << FFlags.ReturnDoesNotAlias; + Out << ")"; + } + if (!FS->calls().empty()) { + Out << ", calls: ("; + FieldSeparator IFS; + for (auto &Call : FS->calls()) { + Out << IFS; + Out << "(callee: ^" << Machine.getGUIDSlot(Call.first.getGUID()); + if (Call.second.getHotness() != CalleeInfo::HotnessType::Unknown) + Out << ", hotness: " << getHotnessName(Call.second.getHotness()); + else if (Call.second.RelBlockFreq) + Out << ", relbf: " << Call.second.RelBlockFreq; + Out << ")"; + } + Out << ")"; + } + + if (const auto *TIdInfo = FS->getTypeIdInfo()) + printTypeIdInfo(*TIdInfo); +} + +void AssemblyWriter::printTypeIdInfo( + const FunctionSummary::TypeIdInfo &TIDInfo) { + Out << ", typeIdInfo: ("; + FieldSeparator TIDFS; + if (!TIDInfo.TypeTests.empty()) { + Out << TIDFS; + Out << "typeTests: ("; + FieldSeparator FS; + for (auto &GUID : TIDInfo.TypeTests) { + Out << FS; + auto Slot = Machine.getGUIDSlot(GUID); + if (Slot != -1) + Out << "^" << Slot; + else + Out << GUID; + } + Out << ")"; + } + if (!TIDInfo.TypeTestAssumeVCalls.empty()) { + Out << TIDFS; + printNonConstVCalls(TIDInfo.TypeTestAssumeVCalls, "typeTestAssumeVCalls"); + } + if (!TIDInfo.TypeCheckedLoadVCalls.empty()) { + Out << TIDFS; + printNonConstVCalls(TIDInfo.TypeCheckedLoadVCalls, "typeCheckedLoadVCalls"); + } + if (!TIDInfo.TypeTestAssumeConstVCalls.empty()) { + Out << TIDFS; + printConstVCalls(TIDInfo.TypeTestAssumeConstVCalls, + "typeTestAssumeConstVCalls"); + } + if (!TIDInfo.TypeCheckedLoadConstVCalls.empty()) { + Out << TIDFS; + printConstVCalls(TIDInfo.TypeCheckedLoadConstVCalls, + "typeCheckedLoadConstVCalls"); + } + Out << ")"; +} + +void AssemblyWriter::printVFuncId(const FunctionSummary::VFuncId VFId) { + Out << "vFuncId: ("; + auto Slot = Machine.getGUIDSlot(VFId.GUID); + if (Slot != -1) + Out << "^" << Slot; + else + Out << "guid: " << VFId.GUID; + Out << ", offset: " << VFId.Offset; + Out << ")"; +} + +void AssemblyWriter::printNonConstVCalls( + const std::vector<FunctionSummary::VFuncId> VCallList, const char *Tag) { + Out << Tag << ": ("; + FieldSeparator FS; + for (auto &VFuncId : VCallList) { + Out << FS; + printVFuncId(VFuncId); + } + Out << ")"; +} + +void AssemblyWriter::printConstVCalls( + const std::vector<FunctionSummary::ConstVCall> VCallList, const char *Tag) { + Out << Tag << ": ("; + FieldSeparator FS; + for (auto &ConstVCall : VCallList) { + Out << FS; + printVFuncId(ConstVCall.VFunc); + if (!ConstVCall.Args.empty()) { + Out << ", "; + printArgs(ConstVCall.Args); + } + } + Out << ")"; +} + +void AssemblyWriter::printSummary(const GlobalValueSummary &Summary) { + GlobalValueSummary::GVFlags GVFlags = Summary.flags(); + GlobalValue::LinkageTypes LT = (GlobalValue::LinkageTypes)GVFlags.Linkage; + Out << getSummaryKindName(Summary.getSummaryKind()) << ": "; + Out << "(module: ^" << Machine.getModulePathSlot(Summary.modulePath()) + << ", flags: ("; + Out << "linkage: " << getLinkageName(LT); + Out << ", notEligibleToImport: " << GVFlags.NotEligibleToImport; + Out << ", live: " << GVFlags.Live; + Out << ", dsoLocal: " << GVFlags.DSOLocal; + Out << ")"; + + if (Summary.getSummaryKind() == GlobalValueSummary::AliasKind) + printAliasSummary(cast<AliasSummary>(&Summary)); + else if (Summary.getSummaryKind() == GlobalValueSummary::FunctionKind) + printFunctionSummary(cast<FunctionSummary>(&Summary)); + else + printGlobalVarSummary(cast<GlobalVarSummary>(&Summary)); + + auto RefList = Summary.refs(); + if (!RefList.empty()) { + Out << ", refs: ("; + FieldSeparator FS; + for (auto &Ref : RefList) { + Out << FS; + Out << "^" << Machine.getGUIDSlot(Ref.getGUID()); + } + Out << ")"; + } + + Out << ")"; +} + +void AssemblyWriter::printSummaryInfo(unsigned Slot, const ValueInfo &VI) { + Out << "^" << Slot << " = gv: ("; + if (!VI.name().empty()) + Out << "name: \"" << VI.name() << "\""; + else + Out << "guid: " << VI.getGUID(); + if (!VI.getSummaryList().empty()) { + Out << ", summaries: ("; + FieldSeparator FS; + for (auto &Summary : VI.getSummaryList()) { + Out << FS; + printSummary(*Summary); + } + Out << ")"; + } + Out << ")"; + if (!VI.name().empty()) + Out << " ; guid = " << VI.getGUID(); + Out << "\n"; +} + static void printMetadataIdentifier(StringRef Name, formatted_raw_ostream &Out) { if (Name.empty()) { @@ -2460,34 +3064,6 @@ void AssemblyWriter::printNamedMDNode(const NamedMDNode *NMD) { Out << "}\n"; } -static const char *getLinkagePrintName(GlobalValue::LinkageTypes LT) { - switch (LT) { - case GlobalValue::ExternalLinkage: - return ""; - case GlobalValue::PrivateLinkage: - return "private "; - case GlobalValue::InternalLinkage: - return "internal "; - case GlobalValue::LinkOnceAnyLinkage: - return "linkonce "; - case GlobalValue::LinkOnceODRLinkage: - return "linkonce_odr "; - case GlobalValue::WeakAnyLinkage: - return "weak "; - case GlobalValue::WeakODRLinkage: - return "weak_odr "; - case GlobalValue::CommonLinkage: - return "common "; - case GlobalValue::AppendingLinkage: - return "appending "; - case GlobalValue::ExternalWeakLinkage: - return "extern_weak "; - case GlobalValue::AvailableExternallyLinkage: - return "available_externally "; - } - llvm_unreachable("invalid linkage"); -} - static void PrintVisibility(GlobalValue::VisibilityTypes Vis, formatted_raw_ostream &Out) { switch (Vis) { @@ -2497,8 +3073,13 @@ static void PrintVisibility(GlobalValue::VisibilityTypes Vis, } } -static void PrintDSOLocation(bool IsDSOLocal, formatted_raw_ostream &Out){ - if (IsDSOLocal) +static void PrintDSOLocation(const GlobalValue &GV, + formatted_raw_ostream &Out) { + // GVs with local linkage or non default visibility are implicitly dso_local, + // so we don't print it. + bool Implicit = GV.hasLocalLinkage() || + (!GV.hasExternalWeakLinkage() && !GV.hasDefaultVisibility()); + if (GV.isDSOLocal() && !Implicit) Out << "dso_local "; } @@ -2571,8 +3152,8 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { if (!GV->hasInitializer() && GV->hasExternalLinkage()) Out << "external "; - Out << getLinkagePrintName(GV->getLinkage()); - PrintDSOLocation(GV->isDSOLocal(), Out); + Out << getLinkageNameWithSpace(GV->getLinkage()); + PrintDSOLocation(*GV, Out); PrintVisibility(GV->getVisibility(), Out); PrintDLLStorageClass(GV->getDLLStorageClass(), Out); PrintThreadLocalModel(GV->getThreadLocalMode(), Out); @@ -2593,7 +3174,7 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { if (GV->hasSection()) { Out << ", section \""; - PrintEscapedString(GV->getSection(), Out); + printEscapedString(GV->getSection(), Out); Out << '"'; } maybePrintComdat(Out, *GV); @@ -2618,8 +3199,8 @@ void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) { WriteAsOperandInternal(Out, GIS, &TypePrinter, &Machine, GIS->getParent()); Out << " = "; - Out << getLinkagePrintName(GIS->getLinkage()); - PrintDSOLocation(GIS->isDSOLocal(), Out); + Out << getLinkageNameWithSpace(GIS->getLinkage()); + PrintDSOLocation(*GIS, Out); PrintVisibility(GIS->getVisibility(), Out); PrintDLLStorageClass(GIS->getDLLStorageClass(), Out); PrintThreadLocalModel(GIS->getThreadLocalMode(), Out); @@ -2656,39 +3237,30 @@ void AssemblyWriter::printComdat(const Comdat *C) { } void AssemblyWriter::printTypeIdentities() { - if (TypePrinter.NumberedTypes.empty() && - TypePrinter.NamedTypes.empty()) + if (TypePrinter.empty()) return; Out << '\n'; - // We know all the numbers that each type is used and we know that it is a - // dense assignment. Convert the map to an index table. - std::vector<StructType*> NumberedTypes(TypePrinter.NumberedTypes.size()); - for (DenseMap<StructType*, unsigned>::iterator I = - TypePrinter.NumberedTypes.begin(), E = TypePrinter.NumberedTypes.end(); - I != E; ++I) { - assert(I->second < NumberedTypes.size() && "Didn't get a dense numbering?"); - NumberedTypes[I->second] = I->first; - } - // Emit all numbered types. - for (unsigned i = 0, e = NumberedTypes.size(); i != e; ++i) { - Out << '%' << i << " = type "; + auto &NumberedTypes = TypePrinter.getNumberedTypes(); + for (unsigned I = 0, E = NumberedTypes.size(); I != E; ++I) { + Out << '%' << I << " = type "; // Make sure we print out at least one level of the type structure, so // that we do not get %2 = type %2 - TypePrinter.printStructBody(NumberedTypes[i], Out); + TypePrinter.printStructBody(NumberedTypes[I], Out); Out << '\n'; } - for (unsigned i = 0, e = TypePrinter.NamedTypes.size(); i != e; ++i) { - PrintLLVMName(Out, TypePrinter.NamedTypes[i]->getName(), LocalPrefix); + auto &NamedTypes = TypePrinter.getNamedTypes(); + for (unsigned I = 0, E = NamedTypes.size(); I != E; ++I) { + PrintLLVMName(Out, NamedTypes[I]->getName(), LocalPrefix); Out << " = type "; // Make sure we print out at least one level of the type structure, so // that we do not get %FILE = type %FILE - TypePrinter.printStructBody(TypePrinter.NamedTypes[i], Out); + TypePrinter.printStructBody(NamedTypes[I], Out); Out << '\n'; } } @@ -2730,8 +3302,8 @@ void AssemblyWriter::printFunction(const Function *F) { } else Out << "define "; - Out << getLinkagePrintName(F->getLinkage()); - PrintDSOLocation(F->isDSOLocal(), Out); + Out << getLinkageNameWithSpace(F->getLinkage()); + PrintDSOLocation(*F, Out); PrintVisibility(F->getVisibility(), Out); PrintDLLStorageClass(F->getDLLStorageClass(), Out); @@ -2786,7 +3358,7 @@ void AssemblyWriter::printFunction(const Function *F) { Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes()); if (F->hasSection()) { Out << " section \""; - PrintEscapedString(F->getSection(), Out); + printEscapedString(F->getSection(), Out); Out << '"'; } maybePrintComdat(Out, *F); @@ -3558,9 +4130,7 @@ static bool printWithoutType(const Value &V, raw_ostream &O, static void printAsOperandImpl(const Value &V, raw_ostream &O, bool PrintType, ModuleSlotTracker &MST) { - TypePrinting TypePrinter; - if (const Module *M = MST.getModule()) - TypePrinter.incorporateTypes(*M); + TypePrinting TypePrinter(MST.getModule()); if (PrintType) { TypePrinter.print(V.getType(), O); O << ' '; @@ -3599,9 +4169,7 @@ static void printMetadataImpl(raw_ostream &ROS, const Metadata &MD, bool OnlyAsOperand) { formatted_raw_ostream OS(ROS); - TypePrinting TypePrinter; - if (M) - TypePrinter.incorporateTypes(*M); + TypePrinting TypePrinter(M); WriteAsOperandInternal(OS, &MD, &TypePrinter, MST.getMachine(), M, /* FromValue */ true); @@ -3635,6 +4203,13 @@ void Metadata::print(raw_ostream &OS, ModuleSlotTracker &MST, printMetadataImpl(OS, *this, MST, M, /* OnlyAsOperand */ false); } +void ModuleSummaryIndex::print(raw_ostream &ROS, bool IsForDebug) const { + SlotTracker SlotTable(this); + formatted_raw_ostream OS(ROS); + AssemblyWriter W(OS, SlotTable, this, IsForDebug); + W.printModuleSummaryIndex(); +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) // Value::dump - allow easy printing of Values from the debugger. LLVM_DUMP_METHOD @@ -3651,7 +4226,7 @@ void Module::dump() const { /*ShouldPreserveUseListOrder=*/false, /*IsForDebug=*/true); } -// \brief Allow printing of Comdats from the debugger. +// Allow printing of Comdats from the debugger. LLVM_DUMP_METHOD void Comdat::dump() const { print(dbgs(), /*IsForDebug=*/true); } @@ -3667,4 +4242,8 @@ void Metadata::dump(const Module *M) const { print(dbgs(), M, /*IsForDebug=*/true); dbgs() << '\n'; } + +// Allow printing of ModuleSummaryIndex from the debugger. +LLVM_DUMP_METHOD +void ModuleSummaryIndex::dump() const { print(dbgs(), /*IsForDebug=*/true); } #endif |