diff options
Diffstat (limited to 'llvm/lib/IR/AsmWriter.cpp')
-rw-r--r-- | llvm/lib/IR/AsmWriter.cpp | 489 |
1 files changed, 486 insertions, 3 deletions
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 359ca1d5054..7659a6b580d 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -59,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" @@ -676,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; @@ -692,6 +696,10 @@ private: DenseMap<AttributeSet, unsigned> asMap; unsigned asNext = 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. /// @@ -709,6 +717,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; @@ -718,6 +729,7 @@ public: int getGlobalSlot(const GlobalValue *V); int getMetadataSlot(const MDNode *N); int getAttributeGroupSlot(AttributeSet AS); + 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. @@ -749,8 +761,12 @@ public: unsigned as_size() const { return asMap.size(); } bool as_empty() const { return asMap.empty(); } - /// This function does the actual initialization. + /// GUID map iterators. + using guid_iterator = DenseMap<GlobalValue::GUID, unsigned>::iterator; + + /// These functions do the actual initialization. inline void initialize(); + void initializeIndex(); // Implementation Details private: @@ -766,9 +782,12 @@ private: /// Insert the specified AttributeSet into the slot table. void CreateAttributeSetSlot(AttributeSet AS); + 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(); @@ -869,6 +888,9 @@ SlotTracker::SlotTracker(const Function *F, bool ShouldInitializeAllMetadata) : TheModule(F ? F->getParent() : nullptr), TheFunction(F), ShouldInitializeAllMetadata(ShouldInitializeAllMetadata) {} +SlotTracker::SlotTracker(const ModuleSummaryIndex *Index) + : TheModule(nullptr), ShouldInitializeAllMetadata(false), TheIndex(Index) {} + inline void SlotTracker::initialize() { if (TheModule) { processModule(); @@ -879,6 +901,13 @@ inline void SlotTracker::initialize() { processFunction(); } +void SlotTracker::initializeIndex() { + 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() { @@ -970,6 +999,24 @@ 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. Start numbering the GUIDs after the module ids. + GUIDNext = TheIndex->modulePaths().size(); + + 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); @@ -1053,6 +1100,15 @@ int SlotTracker::getAttributeGroupSlot(AttributeSet AS) { return AI == asMap.end() ? -1 : (int)AI->second; } +int SlotTracker::getGUIDSlot(GlobalValue::GUID GUID) { + // Check for uninitialized state and do lazy initialization. + initializeIndex(); + + // 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!"); @@ -1113,6 +1169,11 @@ void SlotTracker::CreateAttributeSetSlot(AttributeSet AS) { asMap[AS] = DestSlot; } +/// Create a new slot for the specified GUID +void SlotTracker::CreateGUIDSlot(GlobalValue::GUID GUID) { + GUIDMap[GUID] = GUIDNext++; +} + //===----------------------------------------------------------------------===// // AsmWriter Implementation //===----------------------------------------------------------------------===// @@ -2193,11 +2254,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; @@ -2205,6 +2267,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 @@ -2212,6 +2275,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); @@ -2247,6 +2313,25 @@ 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: /// Print out metadata attachments. void printMetadataAttachments( @@ -2277,6 +2362,11 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, 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!>"; @@ -2478,6 +2568,210 @@ void AssemblyWriter::printModule(const Module *M) { } } +void AssemblyWriter::printModuleSummaryIndex() { + assert(TheIndex); + Machine.initializeIndex(); + + Out << "\n"; + + // Print module path entries, using the module id as the slot number. To + // print in order, add paths to a vector indexed by module id. + std::vector<std::pair<StringRef, ModuleHash>> moduleVec; + std::string RegularLTOModuleName = "[Regular LTO]"; + moduleVec.resize(TheIndex->modulePaths().size()); + for (auto &ModPath : TheIndex->modulePaths()) { + // A module id of -1 is a special entry for a regular LTO module created + // during the thin link. + if (ModPath.second.first == -1u) + moduleVec[TheIndex->modulePaths().size() - 1] = + std::make_pair(RegularLTOModuleName, ModPath.second.second); + else { + assert(ModPath.second.first < moduleVec.size()); + moduleVec[ModPath.second.first] = + std::make_pair(ModPath.first(), ModPath.second.second); + } + } + unsigned i = 0; + for (auto &ModPair : moduleVec) { + Out << "^" << i++ << " = module: ("; + Out << "path: \"" << ModPair.first << "\""; + 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: ^" + << Machine.getGUIDSlot(SummaryToGUIDMap[&AS->getAliasee()]); +} + +void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) { + // Nothing for now +} + static std::string getLinkageName(GlobalValue::LinkageTypes LT) { switch (LT) { case GlobalValue::ExternalLinkage: @@ -2515,6 +2809,184 @@ static std::string getLinkageNameWithSpace(GlobalValue::LinkageTypes LT) { 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: ^" << TheIndex->getModuleId(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()) { @@ -3700,6 +4172,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 @@ -3732,4 +4211,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 |