diff options
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/llvm-dis/llvm-dis.cpp | 14 | ||||
-rw-r--r-- | llvm/tools/llvm-ir2vec/CMakeLists.txt | 10 | ||||
-rw-r--r-- | llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp | 314 | ||||
-rw-r--r-- | llvm/tools/llvm-mc/Disassembler.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/llvm-objdump.cpp | 180 | ||||
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 50 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 2 |
7 files changed, 459 insertions, 117 deletions
diff --git a/llvm/tools/llvm-dis/llvm-dis.cpp b/llvm/tools/llvm-dis/llvm-dis.cpp index 422eb85..2b43d27 100644 --- a/llvm/tools/llvm-dis/llvm-dis.cpp +++ b/llvm/tools/llvm-dis/llvm-dis.cpp @@ -131,20 +131,6 @@ public: printDebugLoc(DL,OS); OS << "]"; } - if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) { - if (!Padded) { - OS.PadToColumn(50); - OS << ";"; - } - OS << " [debug variable = " << DDI->getVariable()->getName() << "]"; - } - else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) { - if (!Padded) { - OS.PadToColumn(50); - OS << ";"; - } - OS << " [debug variable = " << DVI->getVariable()->getName() << "]"; - } } } }; diff --git a/llvm/tools/llvm-ir2vec/CMakeLists.txt b/llvm/tools/llvm-ir2vec/CMakeLists.txt new file mode 100644 index 0000000..a4cf969 --- /dev/null +++ b/llvm/tools/llvm-ir2vec/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Core + IRReader + Support + ) + +add_llvm_tool(llvm-ir2vec + llvm-ir2vec.cpp + ) diff --git a/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp b/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp new file mode 100644 index 0000000..e1e5fad --- /dev/null +++ b/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp @@ -0,0 +1,314 @@ +//===- llvm-ir2vec.cpp - IR2Vec Embedding Generation Tool -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the IR2Vec embedding generation tool. +/// +/// This tool provides two main functionalities: +/// +/// 1. Triplet Generation Mode (--mode=triplets): +/// Generates triplets (opcode, type, operands) for vocabulary training. +/// Usage: llvm-ir2vec --mode=triplets input.bc -o triplets.txt +/// +/// 2. Embedding Generation Mode (--mode=embeddings): +/// Generates IR2Vec embeddings using a trained vocabulary. +/// Usage: llvm-ir2vec --mode=embeddings --ir2vec-vocab-path=vocab.json +/// --level=func input.bc -o embeddings.txt Levels: --level=inst +/// (instructions), --level=bb (basic blocks), --level=func (functions) +/// (See IR2Vec.cpp for more embedding generation options) +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/IR2Vec.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassInstrumentation.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Type.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "ir2vec" + +namespace llvm { +namespace ir2vec { + +static cl::OptionCategory IR2VecToolCategory("IR2Vec Tool Options"); + +static cl::opt<std::string> + InputFilename(cl::Positional, + cl::desc("<input bitcode file or '-' for stdin>"), + cl::init("-"), cl::cat(IR2VecToolCategory)); + +static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), + cl::value_desc("filename"), + cl::init("-"), + cl::cat(IR2VecToolCategory)); + +enum ToolMode { + TripletMode, // Generate triplets for vocabulary training + EmbeddingMode // Generate embeddings using trained vocabulary +}; + +static cl::opt<ToolMode> + Mode("mode", cl::desc("Tool operation mode:"), + cl::values(clEnumValN(TripletMode, "triplets", + "Generate triplets for vocabulary training"), + clEnumValN(EmbeddingMode, "embeddings", + "Generate embeddings using trained vocabulary")), + cl::init(EmbeddingMode), cl::cat(IR2VecToolCategory)); + +static cl::opt<std::string> + FunctionName("function", cl::desc("Process specific function only"), + cl::value_desc("name"), cl::Optional, cl::init(""), + cl::cat(IR2VecToolCategory)); + +enum EmbeddingLevel { + InstructionLevel, // Generate instruction-level embeddings + BasicBlockLevel, // Generate basic block-level embeddings + FunctionLevel // Generate function-level embeddings +}; + +static cl::opt<EmbeddingLevel> + Level("level", cl::desc("Embedding generation level (for embedding mode):"), + cl::values(clEnumValN(InstructionLevel, "inst", + "Generate instruction-level embeddings"), + clEnumValN(BasicBlockLevel, "bb", + "Generate basic block-level embeddings"), + clEnumValN(FunctionLevel, "func", + "Generate function-level embeddings")), + cl::init(FunctionLevel), cl::cat(IR2VecToolCategory)); + +namespace { + +/// Helper class for collecting IR triplets and generating embeddings +class IR2VecTool { +private: + Module &M; + ModuleAnalysisManager MAM; + const Vocabulary *Vocab = nullptr; + +public: + explicit IR2VecTool(Module &M) : M(M) {} + + /// Initialize the IR2Vec vocabulary analysis + bool initializeVocabulary() { + // Register and run the IR2Vec vocabulary analysis + // The vocabulary file path is specified via --ir2vec-vocab-path global + // option + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + MAM.registerPass([&] { return IR2VecVocabAnalysis(); }); + Vocab = &MAM.getResult<IR2VecVocabAnalysis>(M); + return Vocab->isValid(); + } + + /// Generate triplets for the entire module + void generateTriplets(raw_ostream &OS) const { + for (const Function &F : M) + generateTriplets(F, OS); + } + + /// Generate triplets for a single function + void generateTriplets(const Function &F, raw_ostream &OS) const { + if (F.isDeclaration()) + return; + + std::string LocalOutput; + raw_string_ostream LocalOS(LocalOutput); + + for (const BasicBlock &BB : F) + traverseBasicBlock(BB, LocalOS); + + LocalOS.flush(); + OS << LocalOutput; + } + + /// Generate embeddings for the entire module + void generateEmbeddings(raw_ostream &OS) const { + if (!Vocab->isValid()) { + OS << "Error: Vocabulary is not valid. IR2VecTool not initialized.\n"; + return; + } + + for (const Function &F : M) + generateEmbeddings(F, OS); + } + + /// Generate embeddings for a single function + void generateEmbeddings(const Function &F, raw_ostream &OS) const { + if (F.isDeclaration()) { + OS << "Function " << F.getName() << " is a declaration, skipping.\n"; + return; + } + + // Create embedder for this function + assert(Vocab->isValid() && "Vocabulary is not valid"); + auto Emb = Embedder::create(IR2VecKind::Symbolic, F, *Vocab); + if (!Emb) { + OS << "Error: Failed to create embedder for function " << F.getName() + << "\n"; + return; + } + + OS << "Function: " << F.getName() << "\n"; + + // Generate embeddings based on the specified level + switch (Level) { + case FunctionLevel: { + Emb->getFunctionVector().print(OS); + break; + } + case BasicBlockLevel: { + const auto &BBVecMap = Emb->getBBVecMap(); + for (const BasicBlock &BB : F) { + auto It = BBVecMap.find(&BB); + if (It != BBVecMap.end()) { + OS << BB.getName() << ":"; + It->second.print(OS); + } + } + break; + } + case InstructionLevel: { + const auto &InstMap = Emb->getInstVecMap(); + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + auto It = InstMap.find(&I); + if (It != InstMap.end()) { + I.print(OS); + It->second.print(OS); + } + } + } + break; + } + } + } + +private: + /// Process a single basic block for triplet generation + void traverseBasicBlock(const BasicBlock &BB, raw_string_ostream &OS) const { + // Consider only non-debug and non-pseudo instructions + for (const auto &I : BB.instructionsWithoutDebug()) { + StringRef OpcStr = Vocabulary::getVocabKeyForOpcode(I.getOpcode()); + StringRef TypeStr = + Vocabulary::getVocabKeyForTypeID(I.getType()->getTypeID()); + + OS << '\n' << OpcStr << ' ' << TypeStr << ' '; + + LLVM_DEBUG({ + I.print(dbgs()); + dbgs() << "\n"; + I.getType()->print(dbgs()); + dbgs() << " Type\n"; + }); + + for (const Use &U : I.operands()) + OS << Vocabulary::getVocabKeyForOperandKind( + Vocabulary::getOperandKind(U.get())) + << ' '; + } + } +}; + +Error processModule(Module &M, raw_ostream &OS) { + IR2VecTool Tool(M); + + if (Mode == EmbeddingMode) { + // Initialize vocabulary for embedding generation + // Note: Requires --ir2vec-vocab-path option to be set + if (!Tool.initializeVocabulary()) + return createStringError( + errc::invalid_argument, + "Failed to initialize IR2Vec vocabulary. " + "Make sure to specify --ir2vec-vocab-path for embedding mode."); + + if (!FunctionName.empty()) { + // Process single function + if (const Function *F = M.getFunction(FunctionName)) + Tool.generateEmbeddings(*F, OS); + else + return createStringError(errc::invalid_argument, + "Function '%s' not found", + FunctionName.c_str()); + } else { + // Process all functions + Tool.generateEmbeddings(OS); + } + } else { + // Triplet generation mode - no vocabulary needed + if (!FunctionName.empty()) + // Process single function + if (const Function *F = M.getFunction(FunctionName)) + Tool.generateTriplets(*F, OS); + else + return createStringError(errc::invalid_argument, + "Function '%s' not found", + FunctionName.c_str()); + else + // Process all functions + Tool.generateTriplets(OS); + } + return Error::success(); +} +} // namespace +} // namespace ir2vec +} // namespace llvm + +int main(int argc, char **argv) { + using namespace llvm; + using namespace llvm::ir2vec; + + InitLLVM X(argc, argv); + cl::HideUnrelatedOptions(IR2VecToolCategory); + cl::ParseCommandLineOptions( + argc, argv, + "IR2Vec - Embedding Generation Tool\n" + "Generates embeddings for a given LLVM IR and " + "supports triplet generation for vocabulary " + "training and embedding generation.\n\n" + "See https://llvm.org/docs/CommandGuide/llvm-ir2vec.html for more " + "information.\n"); + + // Validate command line options + if (Mode == TripletMode && Level.getNumOccurrences() > 0) + errs() << "Warning: --level option is ignored in triplet mode\n"; + + // Parse the input LLVM IR file or stdin + SMDiagnostic Err; + LLVMContext Context; + std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context); + if (!M) { + Err.print(argv[0], errs()); + return 1; + } + + std::error_code EC; + raw_fd_ostream OS(OutputFilename, EC); + if (EC) { + errs() << "Error opening output file: " << EC.message() << "\n"; + return 1; + } + + if (Error Err = processModule(*M, OS)) { + handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EIB) { + errs() << "Error: " << EIB.message() << "\n"; + }); + return 1; + } + + return 0; +} diff --git a/llvm/tools/llvm-mc/Disassembler.cpp b/llvm/tools/llvm-mc/Disassembler.cpp index 607184e..8672793 100644 --- a/llvm/tools/llvm-mc/Disassembler.cpp +++ b/llvm/tools/llvm-mc/Disassembler.cpp @@ -45,7 +45,11 @@ static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes, MCInst Inst; MCDisassembler::DecodeStatus S; - S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls()); + if (STI.getTargetTriple().getArch() == Triple::hexagon) + S = DisAsm.getInstructionBundle(Inst, Size, Data.slice(Index), Index, + nulls()); + else + S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls()); switch (S) { case MCDisassembler::Fail: SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]), diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index c5967cd..74eb903 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -693,6 +693,30 @@ public: } else OS << "\t<unknown>"; } + + virtual void emitPostInstructionInfo(formatted_raw_ostream &FOS, + const MCAsmInfo &MAI, + const MCSubtargetInfo &STI, + StringRef Comments, + LiveVariablePrinter &LVP) { + do { + if (!Comments.empty()) { + // Emit a line of comments. + StringRef Comment; + std::tie(Comment, Comments) = Comments.split('\n'); + // MAI.getCommentColumn() assumes that instructions are printed at the + // position of 8, while getInstStartColumn() returns the actual + // position. + unsigned CommentColumn = + MAI.getCommentColumn() - 8 + getInstStartColumn(STI); + FOS.PadToColumn(CommentColumn); + FOS << MAI.getCommentString() << ' ' << Comment; + } + LVP.printAfterInst(FOS); + FOS << "\n"; + } while (!Comments.empty()); + FOS.flush(); + } }; PrettyPrinter PrettyPrinterInst; @@ -714,6 +738,35 @@ public: } } } + + std::string getInstructionSeparator() const { + SmallString<40> Separator; + raw_svector_ostream OS(Separator); + if (ShouldClosePacket) { + OS << " }"; + if (IsLoop0 || IsLoop1) + OS << " "; + if (IsLoop0) + OS << (IsLoop1 ? ":endloop01" : ":endloop0"); + else if (IsLoop1) + OS << ":endloop1"; + } + OS << '\n'; + return OS.str().str(); + } + + void emitPostInstructionInfo(formatted_raw_ostream &FOS, const MCAsmInfo &MAI, + const MCSubtargetInfo &STI, StringRef Comments, + LiveVariablePrinter &LVP) override { + // Hexagon does not write anything to the comment stream, so we can just + // print the separator. + LVP.printAfterInst(FOS); + FOS << getInstructionSeparator(); + FOS.flush(); + if (ShouldClosePacket) + reset(); + } + void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, object::SectionedAddress Address, formatted_raw_ostream &OS, StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, @@ -724,60 +777,64 @@ public: if (!MI) { printLead(Bytes, Address.Address, OS); OS << " <unknown>"; + reset(); return; } - std::string Buffer; + + StringRef Preamble = IsStartOfBundle ? " { " : " "; + + if (SP && (PrintSource || PrintLines)) + SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); + printLead(Bytes, Address.Address, OS); + OS << Preamble; + std::string Buf; { - raw_string_ostream TempStream(Buffer); + raw_string_ostream TempStream(Buf); IP.printInst(MI, Address.Address, "", STI, TempStream); } - StringRef Contents(Buffer); - // Split off bundle attributes - auto PacketBundle = Contents.rsplit('\n'); - // Split off first instruction from the rest - auto HeadTail = PacketBundle.first.split('\n'); - auto Preamble = " { "; - auto Separator = ""; - - // Hexagon's packets require relocations to be inline rather than - // clustered at the end of the packet. - std::vector<RelocationRef>::const_iterator RelCur = Rels->begin(); - std::vector<RelocationRef>::const_iterator RelEnd = Rels->end(); - auto PrintReloc = [&]() -> void { - while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { - if (RelCur->getOffset() == Address.Address) { - printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false); - return; - } - ++RelCur; - } - }; + StringRef Contents(Buf); + + auto Duplex = Contents.split('\v'); + bool HasDuplex = !Duplex.second.empty(); + if (HasDuplex) { + OS << Duplex.first; + OS << "; "; + OS << Duplex.second; + } else { + OS << Duplex.first; + } - while (!HeadTail.first.empty()) { - OS << Separator; - Separator = "\n"; - if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); - printLead(Bytes, Address.Address, OS); - OS << Preamble; - Preamble = " "; - StringRef Inst; - auto Duplex = HeadTail.first.split('\v'); - if (!Duplex.second.empty()) { - OS << Duplex.first; - OS << "; "; - Inst = Duplex.second; - } + uint32_t Instruction = support::endian::read32le(Bytes.data()); + + uint32_t ParseMask = 0x0000c000; + uint32_t PacketEndMask = 0x0000c000; + uint32_t LoopEndMask = 0x00008000; + uint32_t ParseBits = Instruction & ParseMask; + + if (ParseBits == LoopEndMask) { + if (IsStartOfBundle) + IsLoop0 = true; else - Inst = HeadTail.first; - OS << Inst; - HeadTail = HeadTail.second.split('\n'); - if (HeadTail.first.empty()) - OS << " } " << PacketBundle.second; - PrintReloc(); - Bytes = Bytes.slice(4); - Address.Address += 4; + IsLoop1 = true; } + + IsStartOfBundle = false; + + if (ParseBits == PacketEndMask || HasDuplex) + ShouldClosePacket = true; + } + +private: + bool IsStartOfBundle = true; + bool IsLoop0 = false; + bool IsLoop1 = false; + bool ShouldClosePacket = false; + + void reset() { + IsStartOfBundle = true; + IsLoop0 = false; + IsLoop1 = false; + ShouldClosePacket = false; } }; HexagonPrettyPrinter HexagonPrettyPrinterInst; @@ -1610,29 +1667,6 @@ static StringRef getSegmentName(const MachOObjectFile *MachO, return ""; } -static void emitPostInstructionInfo(formatted_raw_ostream &FOS, - const MCAsmInfo &MAI, - const MCSubtargetInfo &STI, - StringRef Comments, - LiveVariablePrinter &LVP) { - do { - if (!Comments.empty()) { - // Emit a line of comments. - StringRef Comment; - std::tie(Comment, Comments) = Comments.split('\n'); - // MAI.getCommentColumn() assumes that instructions are printed at the - // position of 8, while getInstStartColumn() returns the actual position. - unsigned CommentColumn = - MAI.getCommentColumn() - 8 + getInstStartColumn(STI); - FOS.PadToColumn(CommentColumn); - FOS << MAI.getCommentString() << ' ' << Comment; - } - LVP.printAfterInst(FOS); - FOS << '\n'; - } while (!Comments.empty()); - FOS.flush(); -} - static void createFakeELFSections(ObjectFile &Obj) { assert(Obj.isELF()); if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) @@ -2526,15 +2560,15 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj, } assert(DT->Context->getAsmInfo()); - emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(), - *DT->SubtargetInfo, CommentStream.str(), LVP); + DT->Printer->emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(), + *DT->SubtargetInfo, + CommentStream.str(), LVP); Comments.clear(); if (BTF) printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP); - // Hexagon handles relocs in pretty printer - if (InlineRelocs && Obj.getArch() != Triple::hexagon) { + if (InlineRelocs) { while (findRel()) { // When --adjust-vma is used, update the address printed. printRelocation(FOS, Obj.getFileName(), *RelCur, diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 45eac90..207ae2d 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -47,7 +47,6 @@ #include <algorithm> #include <cmath> #include <optional> -#include <queue> using namespace llvm; using ProfCorrelatorKind = InstrProfCorrelator::ProfCorrelatorKind; @@ -2849,9 +2848,8 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) { auto FS = vfs::getRealFileSystem(); auto ReaderOrErr = InstrProfReader::create(Filename, *FS); std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs); - if (ShowDetailedSummary && Cutoffs.empty()) { + if (Cutoffs.empty() && (ShowDetailedSummary || ShowHotFuncList)) Cutoffs = ProfileSummaryBuilder::DefaultCutoffs; - } InstrProfSummaryBuilder Builder(std::move(Cutoffs)); if (Error E = ReaderOrErr.takeError()) exitWithError(std::move(E), Filename); @@ -2863,15 +2861,7 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) { int NumVPKind = IPVK_Last - IPVK_First + 1; std::vector<ValueSitesStats> VPStats(NumVPKind); - auto MinCmp = [](const std::pair<std::string, uint64_t> &v1, - const std::pair<std::string, uint64_t> &v2) { - return v1.second > v2.second; - }; - - std::priority_queue<std::pair<std::string, uint64_t>, - std::vector<std::pair<std::string, uint64_t>>, - decltype(MinCmp)> - HottestFuncs(MinCmp); + std::vector<std::pair<StringRef, uint64_t>> NameAndMaxCount; if (!TextFormat && OnlyListBelow) { OS << "The list of functions with the maximum counter less than " @@ -2946,15 +2936,8 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) { } else if (OnlyListBelow) continue; - if (TopNFunctions) { - if (HottestFuncs.size() == TopNFunctions) { - if (HottestFuncs.top().second < FuncMax) { - HottestFuncs.pop(); - HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax)); - } - } else - HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax)); - } + if (TopNFunctions || ShowHotFuncList) + NameAndMaxCount.emplace_back(Func.Name, FuncMax); if (Show) { if (!ShownFunctions) @@ -3034,16 +3017,27 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) { << "): " << PS->getNumFunctions() - BelowCutoffFunctions << "\n"; } + // Sort by MaxCount in decreasing order + llvm::stable_sort(NameAndMaxCount, [](const auto &L, const auto &R) { + return L.second > R.second; + }); if (TopNFunctions) { - std::vector<std::pair<std::string, uint64_t>> SortedHottestFuncs; - while (!HottestFuncs.empty()) { - SortedHottestFuncs.emplace_back(HottestFuncs.top()); - HottestFuncs.pop(); - } OS << "Top " << TopNFunctions << " functions with the largest internal block counts: \n"; - for (auto &hotfunc : llvm::reverse(SortedHottestFuncs)) - OS << " " << hotfunc.first << ", max count = " << hotfunc.second << "\n"; + auto TopFuncs = ArrayRef(NameAndMaxCount).take_front(TopNFunctions); + for (auto [Name, MaxCount] : TopFuncs) + OS << " " << Name << ", max count = " << MaxCount << "\n"; + } + + if (ShowHotFuncList) { + auto HotCountThreshold = + ProfileSummaryBuilder::getHotCountThreshold(PS->getDetailedSummary()); + OS << "# Hot count threshold: " << HotCountThreshold << "\n"; + for (auto [Name, MaxCount] : NameAndMaxCount) { + if (MaxCount < HotCountThreshold) + break; + OS << Name << "\n"; + } } if (ShownFunctions && ShowIndirectCallTargets) { diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 465c1896..ccc64fe 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -5511,7 +5511,7 @@ template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) { return {"", "", /*IsValid=*/false}; static const char *OSNames[] = { - "Linux", "Hurd", "Solaris", "FreeBSD", "NetBSD", "Syllable", "NaCl", + "Linux", "Hurd", "Solaris", "FreeBSD", "NetBSD", "Syllable", }; StringRef OSName = "Unknown"; if (Words[0] < std::size(OSNames)) |