diff options
Diffstat (limited to 'tools')
39 files changed, 753 insertions, 261 deletions
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index 9fb968cb5d25..0fdc690dab4d 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -2366,7 +2366,7 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, continue; } - Val.extractValue(Data, &Offset, &Unit); + Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit); CompileUnit *ReferencedCU; if (auto RefDie = resolveDIEReference(*this, Units, Val, Unit, Die, ReferencedCU)) { @@ -2965,7 +2965,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE( DWARFFormValue Val(AttrSpec.Form); uint32_t AttrSize = Offset; - Val.extractValue(Data, &Offset, &U); + Val.extractValue(Data, &Offset, U.getFormParams(), &U); AttrSize = Offset - AttrSize; OutOffset += @@ -3158,7 +3158,7 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, DWARFDataExtractor LineExtractor( OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getLineSection(), OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize()); - LineTable.parse(LineExtractor, &StmtOffset); + LineTable.parse(LineExtractor, &StmtOffset, &Unit.getOrigUnit()); // This vector is the output line table. std::vector<DWARFDebugLine::Row> NewRows; diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp index b6d6c909abcf..9d9a24183798 100644 --- a/tools/dsymutil/dsymutil.cpp +++ b/tools/dsymutil/dsymutil.cpp @@ -93,8 +93,8 @@ static list<std::string> ArchFlags( "arch", desc("Link DWARF debug information only for specified CPU architecture\n" "types. This option can be specified multiple times, once for each\n" - "desired architecture. All cpu architectures will be linked by\n" - "default."), + "desired architecture. All CPU architectures will be linked by\n" + "default."), value_desc("arch"), ZeroOrMore, cat(DsymCategory)); static opt<bool> @@ -338,7 +338,6 @@ int main(int argc, char **argv) { NumThreads = 1; NumThreads = std::min<unsigned>(NumThreads, DebugMapPtrsOrErr->size()); - llvm::ThreadPool Threads(NumThreads); // If there is more than one link to execute, we need to generate // temporary files. @@ -366,17 +365,19 @@ int main(int argc, char **argv) { // FIXME: The DwarfLinker can have some very deep recursion that can max // out the (significantly smaller) stack when using threads. We don't // want this limitation when we only have a single thread. - if (NumThreads == 1) + if (NumThreads == 1) { LinkLambda(); - else + } else { + llvm::ThreadPool Threads(NumThreads); Threads.async(LinkLambda); + Threads.wait(); + } if (NeedsTempFiles) TempFiles.emplace_back(Map->getTriple().getArchName().str(), OutputFile); } - Threads.wait(); if (NeedsTempFiles && !MachOUtils::generateUniversalBinary( diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 731bcbd8ac9d..2970a59beee2 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -17,3 +17,9 @@ add_llvm_tool(llvm-ar add_llvm_tool_symlink(llvm-ranlib llvm-ar) add_llvm_tool_symlink(llvm-lib llvm-ar) add_llvm_tool_symlink(llvm-dlltool llvm-ar) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(ar llvm-ar) + add_llvm_tool_symlink(dlltool llvm-ar) + add_llvm_tool_symlink(ranlib llvm-ar) +endif() diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 576265cfe598..8c19f6b6af87 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -127,6 +127,8 @@ static cl::extrahelp MoreHelp( " [v] - be verbose about actions taken\n" ); +static const char OptionChars[] = "dmpqrtxabiosSTucv"; + // This enumeration delineates the kinds of operations on an archive // that are permitted. enum ArchiveOperation { @@ -864,6 +866,24 @@ int main(int argc, char **argv) { Stem.find("lib") != StringRef::npos) return libDriverMain(makeArrayRef(argv, argc)); + for (int i = 1; i < argc; i++) { + // If an argument starts with a dash and only contains chars + // that belong to the options chars set, remove the dash. + // We can't handle it after the command line options parsing + // is done, since it will error out on an unrecognized string + // starting with a dash. + // Make sure this doesn't match the actual llvm-ar specific options + // that start with a dash. + StringRef S = argv[i]; + if (S.startswith("-") && + S.find_first_not_of(OptionChars, 1) == StringRef::npos) { + argv[i]++; + break; + } + if (S == "--") + break; + } + // Have the command line options parsed and handle things // like --help and --version. cl::ParseCommandLineOptions(argc, argv, diff --git a/tools/llvm-cfi-verify/CMakeLists.txt b/tools/llvm-cfi-verify/CMakeLists.txt index 07c6504bf48e..de6a46e78595 100644 --- a/tools/llvm-cfi-verify/CMakeLists.txt +++ b/tools/llvm-cfi-verify/CMakeLists.txt @@ -4,11 +4,11 @@ set(LLVM_LINK_COMPONENTS AllTargetsDescs AllTargetsDisassemblers AllTargetsInfos - DebugInfoDWARF MC MCParser Object Support + Symbolize ) add_llvm_tool(llvm-cfi-verify diff --git a/tools/llvm-cfi-verify/LLVMBuild.txt b/tools/llvm-cfi-verify/LLVMBuild.txt index 5c4ce2630903..d5e932302728 100644 --- a/tools/llvm-cfi-verify/LLVMBuild.txt +++ b/tools/llvm-cfi-verify/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-cfi-verify parent = Tools -required_libraries = all-targets DebugInfoDWARF MC MCDisassembler MCParser Support +required_libraries = all-targets MC MCDisassembler MCParser Support Symbolize diff --git a/tools/llvm-cfi-verify/lib/CMakeLists.txt b/tools/llvm-cfi-verify/lib/CMakeLists.txt index c90e4ed485ea..cd728e004b26 100644 --- a/tools/llvm-cfi-verify/lib/CMakeLists.txt +++ b/tools/llvm-cfi-verify/lib/CMakeLists.txt @@ -11,5 +11,7 @@ llvm_map_components_to_libnames(libs MC MCParser Object - Support) + Support + Symbolize) target_link_libraries(LLVMCFIVerify ${libs}) +set_target_properties(LLVMCFIVerify PROPERTIES FOLDER "Libraries")
\ No newline at end of file diff --git a/tools/llvm-cfi-verify/lib/FileAnalysis.cpp b/tools/llvm-cfi-verify/lib/FileAnalysis.cpp index 278e861dfd3a..0d4e1f497ff8 100644 --- a/tools/llvm-cfi-verify/lib/FileAnalysis.cpp +++ b/tools/llvm-cfi-verify/lib/FileAnalysis.cpp @@ -39,22 +39,20 @@ #include <functional> using Instr = llvm::cfi_verify::FileAnalysis::Instr; +using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer; namespace llvm { namespace cfi_verify { -static cl::opt<bool> IgnoreDWARF( +bool IgnoreDWARFFlag; + +static cl::opt<bool, true> IgnoreDWARFArg( "ignore-dwarf", cl::desc( "Ignore all DWARF data. This relaxes the requirements for all " "statically linked libraries to have been compiled with '-g', but " "will result in false positives for 'CFI unprotected' instructions."), - cl::init(false)); - -cl::opt<unsigned long long> DWARFSearchRange( - "dwarf-search-range", - cl::desc("Address search range used to determine if instruction is valid."), - cl::init(0x10)); + cl::location(IgnoreDWARFFlag), cl::init(false)); Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) { // Open the filename provided. @@ -256,12 +254,16 @@ const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const { return MIA.get(); } +LLVMSymbolizer &FileAnalysis::getSymbolizer() { return *Symbolizer; } + Error FileAnalysis::initialiseDisassemblyMembers() { std::string TripleName = ObjectTriple.getTriple(); ArchName = ""; MCPU = ""; std::string ErrorString; + Symbolizer.reset(new LLVMSymbolizer()); + ObjectTarget = TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString); if (!ObjectTarget) @@ -308,8 +310,8 @@ Error FileAnalysis::initialiseDisassemblyMembers() { } Error FileAnalysis::parseCodeSections() { - if (!IgnoreDWARF) { - DWARF.reset(DWARFContext::create(*Object).release()); + if (!IgnoreDWARFFlag) { + std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object); if (!DWARF) return make_error<StringError>("Could not create DWARF information.", inconvertibleErrorCode()); @@ -347,21 +349,9 @@ Error FileAnalysis::parseCodeSections() { return Error::success(); } -DILineInfoTable FileAnalysis::getLineInfoForAddressRange(uint64_t Address) { - if (!hasLineTableInfo()) - return DILineInfoTable(); - - return DWARF->getLineInfoForAddressRange(Address, DWARFSearchRange); -} - -bool FileAnalysis::hasValidLineInfoForAddressRange(uint64_t Address) { - return !getLineInfoForAddressRange(Address).empty(); -} - -bool FileAnalysis::hasLineTableInfo() const { return DWARF != nullptr; } - void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes, uint64_t SectionAddress) { + assert(Symbolizer && "Symbolizer is uninitialised."); MCInst Instruction; Instr InstrMeta; uint64_t InstructionSize; @@ -381,8 +371,19 @@ void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes, InstrMeta.Valid = ValidInstruction; // Check if this instruction exists in the range of the DWARF metadata. - if (hasLineTableInfo() && !hasValidLineInfoForAddressRange(VMAddress)) - continue; + if (!IgnoreDWARFFlag) { + auto LineInfo = + Symbolizer->symbolizeCode(Object->getFileName(), VMAddress); + if (!LineInfo) { + handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) { + errs() << "Symbolizer failed to get line: " << E.message() << "\n"; + }); + continue; + } + + if (LineInfo->FileName == "<invalid>") + continue; + } addInstruction(InstrMeta); diff --git a/tools/llvm-cfi-verify/lib/FileAnalysis.h b/tools/llvm-cfi-verify/lib/FileAnalysis.h index 9945a2110a28..e0eecb037c37 100644 --- a/tools/llvm-cfi-verify/lib/FileAnalysis.h +++ b/tools/llvm-cfi-verify/lib/FileAnalysis.h @@ -12,7 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -44,6 +44,8 @@ namespace llvm { namespace cfi_verify { +extern bool IgnoreDWARFFlag; + // Disassembler and analysis tool for machine code files. Keeps track of non- // sequential control flows, including indirect control flow instructions. class FileAnalysis { @@ -120,6 +122,7 @@ public: const MCRegisterInfo *getRegisterInfo() const; const MCInstrInfo *getMCInstrInfo() const; const MCInstrAnalysis *getMCInstrAnalysis() const; + symbolize::LLVMSymbolizer &getSymbolizer(); // Returns true if this class is using DWARF line tables for elimination. bool hasLineTableInfo() const; @@ -175,8 +178,8 @@ private: std::unique_ptr<const MCInstrAnalysis> MIA; std::unique_ptr<MCInstPrinter> Printer; - // DWARF debug information. - std::unique_ptr<DWARFContext> DWARF; + // Symbolizer used for debug information parsing. + std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer; // A mapping between the virtual memory address to the instruction metadata // struct. TODO(hctim): Reimplement this as a sorted vector to avoid per- diff --git a/tools/llvm-cfi-verify/lib/LLVMBuild.txt b/tools/llvm-cfi-verify/lib/LLVMBuild.txt index 99b678fc88a1..c0ae1905521a 100644 --- a/tools/llvm-cfi-verify/lib/LLVMBuild.txt +++ b/tools/llvm-cfi-verify/lib/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = CFIVerify parent = Libraries -required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support +required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support Symbolize diff --git a/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/tools/llvm-cfi-verify/llvm-cfi-verify.cpp index d4a46fcc226b..3b4a5c155d04 100644 --- a/tools/llvm-cfi-verify/llvm-cfi-verify.cpp +++ b/tools/llvm-cfi-verify/llvm-cfi-verify.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/SpecialCaseList.h" #include <cstdlib> @@ -32,48 +33,122 @@ using namespace llvm::cfi_verify; cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"), cl::Required); +cl::opt<std::string> BlacklistFilename(cl::Positional, + cl::desc("[blacklist file]"), + cl::init("-")); ExitOnError ExitOnErr; -void printIndirectCFInstructions(FileAnalysis &Analysis) { - uint64_t ProtectedCount = 0; - uint64_t UnprotectedCount = 0; +void printIndirectCFInstructions(FileAnalysis &Analysis, + const SpecialCaseList *SpecialCaseList) { + uint64_t ExpectedProtected = 0; + uint64_t UnexpectedProtected = 0; + uint64_t ExpectedUnprotected = 0; + uint64_t UnexpectedUnprotected = 0; + + symbolize::LLVMSymbolizer &Symbolizer = Analysis.getSymbolizer(); for (uint64_t Address : Analysis.getIndirectInstructions()) { const auto &InstrMeta = Analysis.getInstructionOrDie(Address); - if (Analysis.isIndirectInstructionCFIProtected(Address)) { + bool CFIProtected = Analysis.isIndirectInstructionCFIProtected(Address); + + if (CFIProtected) outs() << "P "; - ProtectedCount++; - } else { + else outs() << "U "; - UnprotectedCount++; - } outs() << format_hex(Address, 2) << " | " << Analysis.getMCInstrInfo()->getName( InstrMeta.Instruction.getOpcode()) - << " "; - outs() << "\n"; - - if (Analysis.hasLineTableInfo()) { - for (const auto &LineKV : Analysis.getLineInfoForAddressRange(Address)) { - outs() << " " << format_hex(LineKV.first, 2) << " = " - << LineKV.second.FileName << ":" << LineKV.second.Line << ":" - << LineKV.second.Column << " (" << LineKV.second.FunctionName - << ")\n"; + << " \n"; + + if (IgnoreDWARFFlag) { + if (CFIProtected) + ExpectedProtected++; + else + UnexpectedUnprotected++; + continue; + } + + auto InliningInfo = Symbolizer.symbolizeInlinedCode(InputFilename, Address); + if (!InliningInfo || InliningInfo->getNumberOfFrames() == 0) { + errs() << "Failed to symbolise " << format_hex(Address, 2) + << " with line tables from " << InputFilename << "\n"; + exit(EXIT_FAILURE); + } + + const auto &LineInfo = + InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1); + + // Print the inlining symbolisation of this instruction. + for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) { + const auto &Line = InliningInfo->getFrame(i); + outs() << " " << format_hex(Address, 2) << " = " << Line.FileName << ":" + << Line.Line << ":" << Line.Column << " (" << Line.FunctionName + << ")\n"; + } + + if (!SpecialCaseList) { + if (CFIProtected) + ExpectedProtected++; + else + UnexpectedUnprotected++; + continue; + } + + bool MatchesBlacklistRule = false; + if (SpecialCaseList->inSection("cfi-icall", "src", LineInfo.FileName) || + SpecialCaseList->inSection("cfi-vcall", "src", LineInfo.FileName)) { + outs() << "BLACKLIST MATCH, 'src'\n"; + MatchesBlacklistRule = true; + } + + if (SpecialCaseList->inSection("cfi-icall", "fun", LineInfo.FunctionName) || + SpecialCaseList->inSection("cfi-vcall", "fun", LineInfo.FunctionName)) { + outs() << "BLACKLIST MATCH, 'fun'\n"; + MatchesBlacklistRule = true; + } + + if (MatchesBlacklistRule) { + if (CFIProtected) { + UnexpectedProtected++; + outs() << "====> Unexpected Protected\n"; + } else { + ExpectedUnprotected++; + outs() << "====> Expected Unprotected\n"; + } + } else { + if (CFIProtected) { + ExpectedProtected++; + outs() << "====> Expected Protected\n"; + } else { + UnexpectedUnprotected++; + outs() << "====> Unexpected Unprotected\n"; } } } - if (ProtectedCount || UnprotectedCount) - outs() << formatv( - "Unprotected: {0} ({1:P}), Protected: {2} ({3:P})\n", UnprotectedCount, - (((double)UnprotectedCount) / (UnprotectedCount + ProtectedCount)), - ProtectedCount, - (((double)ProtectedCount) / (UnprotectedCount + ProtectedCount))); - else + uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected + + ExpectedUnprotected + UnexpectedUnprotected; + + if (IndirectCFInstructions == 0) { outs() << "No indirect CF instructions found.\n"; + return; + } + + outs() << formatv("Expected Protected: {0} ({1:P})\n" + "Unexpected Protected: {2} ({3:P})\n" + "Expected Unprotected: {4} ({5:P})\n" + "Unexpected Unprotected (BAD): {6} ({7:P})\n", + ExpectedProtected, + ((double)ExpectedProtected) / IndirectCFInstructions, + UnexpectedProtected, + ((double)UnexpectedProtected) / IndirectCFInstructions, + ExpectedUnprotected, + ((double)ExpectedUnprotected) / IndirectCFInstructions, + UnexpectedUnprotected, + ((double)UnexpectedUnprotected) / IndirectCFInstructions); } int main(int argc, char **argv) { @@ -89,8 +164,18 @@ int main(int argc, char **argv) { InitializeAllAsmParsers(); InitializeAllDisassemblers(); + std::unique_ptr<SpecialCaseList> SpecialCaseList; + if (BlacklistFilename != "-") { + std::string Error; + SpecialCaseList = SpecialCaseList::create({BlacklistFilename}, Error); + if (!SpecialCaseList) { + errs() << "Failed to get blacklist: " << Error << "\n"; + exit(EXIT_FAILURE); + } + } + FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename)); - printIndirectCFInstructions(Analysis); + printIndirectCFInstructions(Analysis, SpecialCaseList.get()); return EXIT_SUCCESS; } diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp index 4df7f015fd18..7776f2aa9a68 100644 --- a/tools/llvm-cov/gcov.cpp +++ b/tools/llvm-cov/gcov.cpp @@ -11,11 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ProfileData/GCOV.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/GCOV.h" #include "llvm/Support/Path.h" #include <system_error> using namespace llvm; diff --git a/tools/llvm-cvtres/llvm-cvtres.cpp b/tools/llvm-cvtres/llvm-cvtres.cpp index 36c15925e84f..433a75f63dcf 100644 --- a/tools/llvm-cvtres/llvm-cvtres.cpp +++ b/tools/llvm-cvtres/llvm-cvtres.cpp @@ -202,7 +202,7 @@ int main(int argc_, const char *argv_[]) { auto FileOrErr = FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize()); if (!FileOrErr) - reportError(OutputFile, FileOrErr.getError()); + reportError(OutputFile, errorToErrorCode(FileOrErr.takeError())); std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr); std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(), FileBuffer->getBufferStart()); diff --git a/tools/llvm-cxxdump/llvm-cxxdump.cpp b/tools/llvm-cxxdump/llvm-cxxdump.cpp index b10759ad05c0..69b1a8ef2099 100644 --- a/tools/llvm-cxxdump/llvm-cxxdump.cpp +++ b/tools/llvm-cxxdump/llvm-cxxdump.cpp @@ -546,11 +546,10 @@ int main(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "LLVM C++ ABI Data Dumper\n"); // Default to stdin if no filename is specified. - if (opts::InputFilenames.size() == 0) - opts::InputFilenames.push_back("-"); - - std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), - dumpInput); - - return EXIT_SUCCESS; -} + if (opts::InputFilenames.size() == 0)
+ opts::InputFilenames.push_back("-");
+
+ llvm::for_each(opts::InputFilenames, dumpInput);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/llvm-cxxfilt/CMakeLists.txt b/tools/llvm-cxxfilt/CMakeLists.txt index 488064d08dab..2a78acad80a8 100644 --- a/tools/llvm-cxxfilt/CMakeLists.txt +++ b/tools/llvm-cxxfilt/CMakeLists.txt @@ -6,3 +6,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-cxxfilt llvm-cxxfilt.cpp ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(c++filt llvm-cxxfilt) +endif() diff --git a/tools/llvm-dwp/CMakeLists.txt b/tools/llvm-dwp/CMakeLists.txt index 98d67e04fe6a..1b5fbddc1f75 100644 --- a/tools/llvm-dwp/CMakeLists.txt +++ b/tools/llvm-dwp/CMakeLists.txt @@ -15,3 +15,7 @@ add_llvm_tool(llvm-dwp DEPENDS intrinsics_gen ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(dwp llvm-dwp) +endif() diff --git a/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp b/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp index 5a0d6ac4f476..96dbc245ed98 100644 --- a/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp +++ b/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/SubtargetFeature.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" @@ -84,7 +85,7 @@ class LLVMFuzzerInputBuffer : public MemoryBuffer { public: LLVMFuzzerInputBuffer(const uint8_t *data_, size_t size_) - : Data(reinterpret_cast<const char *>(data_)), + : Data(reinterpret_cast<const char *>(data_)), Size(size_) { init(Data, Data+Size, false); } @@ -230,7 +231,8 @@ int AssembleOneInput(const uint8_t *Data, size_t Size) { MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU, MCOptions); Str.reset(TheTarget->createMCObjectStreamer( - TheTriple, Ctx, *MAB, *OS, CE, *STI, MCOptions.MCRelaxAll, + TheTriple, Ctx, std::unique_ptr<MCAsmBackend>(MAB), *OS, + std::unique_ptr<MCCodeEmitter>(CE), *STI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ false)); } diff --git a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp index 0be3c715eee4..db57a6bdaa82 100644 --- a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp +++ b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp @@ -217,10 +217,9 @@ int main(int argc, char **argv) { ToolName = argv[0]; // If no input files specified, read from stdin. - if (InputFilenames.size() == 0) - InputFilenames.push_back("-"); - - std::for_each(InputFilenames.begin(), InputFilenames.end(), - parseMCMarkup); - return 0; -} + if (InputFilenames.size() == 0)
+ InputFilenames.push_back("-");
+
+ llvm::for_each(InputFilenames, parseMCMarkup);
+ return 0;
+}
diff --git a/tools/llvm-mt/llvm-mt.cpp b/tools/llvm-mt/llvm-mt.cpp index 9bc9d332ebf5..23cedb056a67 100644 --- a/tools/llvm-mt/llvm-mt.cpp +++ b/tools/llvm-mt/llvm-mt.cpp @@ -146,10 +146,10 @@ int main(int argc, const char **argv) { std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest(); if (!OutputBuffer) reportError("empty manifest not written"); - ErrorOr<std::unique_ptr<FileOutputBuffer>> FileOrErr = + Expected<std::unique_ptr<FileOutputBuffer>> FileOrErr = FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize()); if (!FileOrErr) - reportError(OutputFile, FileOrErr.getError()); + reportError(OutputFile, errorToErrorCode(FileOrErr.takeError())); std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr); std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(), FileBuffer->getBufferStart()); diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt index 08bcd5f30898..f093cc4328ae 100644 --- a/tools/llvm-nm/CMakeLists.txt +++ b/tools/llvm-nm/CMakeLists.txt @@ -14,3 +14,7 @@ add_llvm_tool(llvm-nm DEPENDS intrinsics_gen ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(nm llvm-nm) +endif() diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 4ad0d95d67f6..d2909644628c 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -85,9 +85,11 @@ cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"), cl::aliasopt(DefinedOnly), cl::Grouping); cl::opt<bool> ExternalOnly("extern-only", - cl::desc("Show only external symbols")); + cl::desc("Show only external symbols"), + cl::ZeroOrMore); cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), - cl::aliasopt(ExternalOnly), cl::Grouping); + cl::aliasopt(ExternalOnly), cl::Grouping, + cl::ZeroOrMore); cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"), cl::Grouping); @@ -946,6 +948,10 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { section_iterator SecI = *SecIOrErr; const coff_section *Section = Obj.getCOFFSection(*SecI); Characteristics = Section->Characteristics; + StringRef SectionName; + Obj.getSectionName(Section, SectionName); + if (SectionName.startswith(".idata")) + return 'i'; } switch (Symb.getSectionNumber()) { @@ -1971,8 +1977,7 @@ int main(int argc, char **argv) { if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly)) error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only"); - std::for_each(InputFilenames.begin(), InputFilenames.end(), - dumpSymbolNamesFromFile); + llvm::for_each(InputFilenames, dumpSymbolNamesFromFile); if (HadError) return 1; diff --git a/tools/llvm-objcopy/CMakeLists.txt b/tools/llvm-objcopy/CMakeLists.txt index 18cc2075345d..05aa727ab9d8 100644 --- a/tools/llvm-objcopy/CMakeLists.txt +++ b/tools/llvm-objcopy/CMakeLists.txt @@ -7,3 +7,7 @@ add_llvm_tool(llvm-objcopy llvm-objcopy.cpp Object.cpp ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objcopy llvm-objcopy) +endif() diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp index 22ae47f1cace..5f9864d9cc04 100644 --- a/tools/llvm-objcopy/Object.cpp +++ b/tools/llvm-objcopy/Object.cpp @@ -685,6 +685,19 @@ template <class ELFT> void ELFObject<ELFT>::sortSections() { CompareSections); } +static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { + // Calculate Diff such that (Offset + Diff) & -Align == Addr & -Align. + if (Align == 0) + Align = 1; + auto Diff = + static_cast<int64_t>(Addr % Align) - static_cast<int64_t>(Offset % Align); + // We only want to add to Offset, however, so if Diff < 0 we can add Align and + // (Offset + Diff) & -Align == Addr & -Align will still hold. + if (Diff < 0) + Diff += Align; + return Offset + Diff; +} + template <class ELFT> void ELFObject<ELFT>::assignOffsets() { // We need a temporary list of segments that has a special order to it // so that we know that anytime ->ParentSegment is set that segment has @@ -728,7 +741,7 @@ template <class ELFT> void ELFObject<ELFT>::assignOffsets() { Segment->Offset = Parent->Offset + Segment->OriginalOffset - Parent->OriginalOffset; } else { - Offset = alignTo(Offset, Segment->Align == 0 ? 1 : Segment->Align); + Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); Segment->Offset = Offset; } Offset = std::max(Offset, Segment->Offset + Segment->FileSize); @@ -829,8 +842,9 @@ template <class ELFT> void BinaryObject<ELFT>::finalize() { uint64_t Offset = 0; for (auto &Segment : this->Segments) { - if (Segment->Type == PT_LOAD && Segment->firstSection() != nullptr) { - Offset = alignTo(Offset, Segment->Align); + if (Segment->Type == llvm::ELF::PT_LOAD && + Segment->firstSection() != nullptr) { + Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); Segment->Offset = Offset; Offset += Segment->FileSize; } diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h index 9c77f5900ce2..f12e6da7d21c 100644 --- a/tools/llvm-objcopy/Object.h +++ b/tools/llvm-objcopy/Object.h @@ -368,6 +368,7 @@ public: Object(const object::ELFObjectFile<ELFT> &Obj); virtual ~Object() = default; + const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function<bool(const SectionBase &)> ToRemove); virtual size_t totalSize() const = 0; virtual void finalize() = 0; diff --git a/tools/llvm-objcopy/llvm-objcopy.cpp b/tools/llvm-objcopy/llvm-objcopy.cpp index f3e9c7750a64..c923f902db82 100644 --- a/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/tools/llvm-objcopy/llvm-objcopy.cpp @@ -83,12 +83,63 @@ static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), cl::aliasopt(ToRemove)); static cl::opt<bool> StripSections("strip-sections", cl::desc("Remove all section headers")); +static cl::opt<bool> + StripDWO("strip-dwo", cl::desc("remove all DWARF .dwo sections from file")); +static cl::opt<bool> ExtractDWO( + "extract-dwo", + cl::desc("remove all sections that are not DWARF .dwo sections from file")); +static cl::opt<std::string> + SplitDWO("split-dwo", + cl::desc("equivalent to extract-dwo on the input file to " + "<dwo-file>, then strip-dwo on the input file"), + cl::value_desc("dwo-file")); using SectionPred = std::function<bool(const SectionBase &Sec)>; -void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { +bool IsDWOSection(const SectionBase &Sec) { + return Sec.Name.endswith(".dwo"); +} + +template <class ELFT> +bool OnlyKeepDWOPred(const Object<ELFT> &Obj, const SectionBase &Sec) { + // We can't remove the section header string table. + if (&Sec == Obj.getSectionHeaderStrTab()) + return false; + // Short of keeping the string table we want to keep everything that is a DWO + // section and remove everything else. + return !IsDWOSection(Sec); +} + +template <class ELFT> +void WriteObjectFile(const Object<ELFT> &Obj, StringRef File) { std::unique_ptr<FileOutputBuffer> Buffer; + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + FileOutputBuffer::create(File, Obj.totalSize(), + FileOutputBuffer::F_executable); + if (BufferOrErr.takeError()) + error("failed to open " + OutputFilename); + else + Buffer = std::move(*BufferOrErr); + Obj.write(*Buffer); + if (auto E = Buffer->commit()) + reportError(File, errorToErrorCode(std::move(E))); +} + +template <class ELFT> +void SplitDWOToFile(const ELFObjectFile<ELFT> &ObjFile, StringRef File) { + // Construct a second output file for the DWO sections. + ELFObject<ELFT> DWOFile(ObjFile); + + DWOFile.removeSections([&](const SectionBase &Sec) { + return OnlyKeepDWOPred<ELFT>(DWOFile, Sec); + }); + DWOFile.finalize(); + WriteObjectFile(DWOFile, File); +} + +void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { std::unique_ptr<Object<ELF64LE>> Obj; + if (!OutputFormat.empty() && OutputFormat != "binary") error("invalid output format '" + OutputFormat + "'"); if (!OutputFormat.empty() && OutputFormat == "binary") @@ -96,6 +147,9 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { else Obj = llvm::make_unique<ELFObject<ELF64LE>>(ObjFile); + if (!SplitDWO.empty()) + SplitDWOToFile<ELF64LE>(ObjFile, SplitDWO.getValue()); + SectionPred RemovePred = [](const SectionBase &) { return false; }; if (!ToRemove.empty()) { @@ -105,6 +159,16 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { }; } + if (StripDWO || !SplitDWO.empty()) + RemovePred = [RemovePred](const SectionBase &Sec) { + return IsDWOSection(Sec) || RemovePred(Sec); + }; + + if (ExtractDWO) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + return OnlyKeepDWOPred(*Obj, Sec) || RemovePred(Sec); + }; + if (StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; @@ -113,21 +177,8 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { } Obj->removeSections(RemovePred); - Obj->finalize(); - ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = - FileOutputBuffer::create(OutputFilename, Obj->totalSize(), - FileOutputBuffer::F_executable); - if (BufferOrErr.getError()) - error("failed to open " + OutputFilename); - else - Buffer = std::move(*BufferOrErr); - std::error_code EC; - if (EC) - report_fatal_error(EC.message()); - Obj->write(*Buffer); - if (auto EC = Buffer->commit()) - reportError(OutputFilename, EC); + WriteObjectFile(*Obj, OutputFilename.getValue()); } int main(int argc, char **argv) { diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index 27e6145dfc13..043a181d6392 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -25,3 +25,7 @@ add_llvm_tool(llvm-objdump if(HAVE_LIBXAR) target_link_libraries(llvm-objdump ${XAR_LIB}) endif() + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objdump llvm-objdump) +endif() diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 09396466c40e..02eaa89f088a 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -865,8 +865,19 @@ static void printRelocationTargetName(const MachOObjectFile *O, } else { section_iterator SI = O->section_begin(); // Adjust for the fact that sections are 1-indexed. - advance(SI, Val - 1); - SI->getName(S); + if (Val == 0) { + fmt << "0 (?,?)"; + return; + } + uint32_t i = Val - 1; + while (i != 0 && SI != O->section_end()) { + i--; + advance(SI, 1); + } + if (SI == O->section_end()) + fmt << Val << " (?,?)"; + else + SI->getName(S); } fmt << S; @@ -2183,11 +2194,10 @@ int main(int argc, char **argv) { && !PrintFaultMaps && DwarfDumpType == DIDT_Null) { cl::PrintHelpMessage(); - return 2; - } - - std::for_each(InputFilenames.begin(), InputFilenames.end(), - DumpInput); - - return EXIT_SUCCESS; -} + return 2;
+ }
+
+ llvm::for_each(InputFilenames, DumpInput);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp index 8b2d5ce179f4..bee9f182e3fb 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -1199,20 +1199,17 @@ int main(int argc_, const char *argv_[]) { opts::pretty::ExcludeCompilands.push_back( "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); - opts::pretty::ExcludeCompilands.push_back( - "d:\\\\th.obj.x86fre\\\\minkernel"); - } - std::for_each(opts::pretty::InputFilenames.begin(), - opts::pretty::InputFilenames.end(), dumpPretty); - } else if (opts::DumpSubcommand) { - std::for_each(opts::dump::InputFilenames.begin(), - opts::dump::InputFilenames.end(), dumpRaw); - } else if (opts::BytesSubcommand) { - std::for_each(opts::bytes::InputFilenames.begin(), - opts::bytes::InputFilenames.end(), dumpBytes); - } else if (opts::DiffSubcommand) { - for (StringRef S : opts::diff::RawModiEquivalences) { - StringRef Left; + opts::pretty::ExcludeCompilands.push_back(
+ "d:\\\\th.obj.x86fre\\\\minkernel");
+ }
+ llvm::for_each(opts::pretty::InputFilenames, dumpPretty);
+ } else if (opts::DumpSubcommand) {
+ llvm::for_each(opts::dump::InputFilenames, dumpRaw);
+ } else if (opts::BytesSubcommand) {
+ llvm::for_each(opts::bytes::InputFilenames, dumpBytes);
+ } else if (opts::DiffSubcommand) {
+ for (StringRef S : opts::diff::RawModiEquivalences) {
+ StringRef Left;
StringRef Right; std::tie(Left, Right) = S.split(','); uint32_t X, Y; diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index 544716741734..dafc9e10cfa1 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -23,3 +23,7 @@ add_llvm_tool(llvm-readobj ) add_llvm_tool_symlink(llvm-readelf llvm-readobj) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(readelf llvm-readobj) +endif() diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 05b7c800cc1b..851988110ea7 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -566,14 +566,13 @@ int main(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); // Default to stdin if no filename is specified. - if (opts::InputFilenames.size() == 0) - opts::InputFilenames.push_back("-"); - - std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), - dumpInput); - - if (opts::CodeViewMergedTypes) { - ScopedPrinter W(outs()); + if (opts::InputFilenames.size() == 0)
+ opts::InputFilenames.push_back("-");
+
+ llvm::for_each(opts::InputFilenames, dumpInput);
+
+ if (opts::CodeViewMergedTypes) {
+ ScopedPrinter W(outs());
dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable); } diff --git a/tools/llvm-size/CMakeLists.txt b/tools/llvm-size/CMakeLists.txt index 60345739c35a..7ef4f1769b84 100644 --- a/tools/llvm-size/CMakeLists.txt +++ b/tools/llvm-size/CMakeLists.txt @@ -6,3 +6,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-size llvm-size.cpp ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(size llvm-size) +endif() diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index bdb118a264e8..7a8e744d2e6e 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -880,14 +880,13 @@ int main(int argc, char **argv) { } if (InputFilenames.size() == 0) - InputFilenames.push_back("a.out"); - - MoreThanOneFile = InputFilenames.size() > 1; - std::for_each(InputFilenames.begin(), InputFilenames.end(), - printFileSectionSizes); - if (OutputFormat == berkeley && TotalSizes) - printBerkelyTotals(); - + InputFilenames.push_back("a.out");
+
+ MoreThanOneFile = InputFilenames.size() > 1;
+ llvm::for_each(InputFilenames, printFileSectionSizes);
+ if (OutputFormat == berkeley && TotalSizes)
+ printBerkelyTotals();
+
if (HadError) return 1; } diff --git a/tools/llvm-strings/CMakeLists.txt b/tools/llvm-strings/CMakeLists.txt index 9339892a4997..390f11751397 100644 --- a/tools/llvm-strings/CMakeLists.txt +++ b/tools/llvm-strings/CMakeLists.txt @@ -8,3 +8,6 @@ add_llvm_tool(llvm-strings llvm-strings.cpp ) +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(strings llvm-strings) +endif() diff --git a/tools/llvm-symbolizer/CMakeLists.txt b/tools/llvm-symbolizer/CMakeLists.txt index b04c45ff7442..d9b05208afd8 100644 --- a/tools/llvm-symbolizer/CMakeLists.txt +++ b/tools/llvm-symbolizer/CMakeLists.txt @@ -14,3 +14,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-symbolizer llvm-symbolizer.cpp ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(addr2line llvm-symbolizer) +endif() diff --git a/tools/llvm-xray/trie-node.h b/tools/llvm-xray/trie-node.h new file mode 100644 index 000000000000..e6ba4e215b91 --- /dev/null +++ b/tools/llvm-xray/trie-node.h @@ -0,0 +1,92 @@ +//===- trie-node.h - XRay Call Stack Data Structure -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a data structure and routines for working with call stacks +// of instrumented functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H +#define LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H + +#include <forward_list> +#include <numeric> + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" + +/// A type to represent a trie of invocations. It is useful to construct a +/// graph of these nodes from reading an XRay trace, such that each function +/// call can be placed in a larger context. +/// +/// The template parameter allows users of the template to attach their own +/// data elements to each node in the invocation graph. +template <typename AssociatedData> struct TrieNode { + /// The function ID. + int32_t FuncId; + + /// The caller of this function. + TrieNode<AssociatedData> *Parent; + + /// The callees from this function. + llvm::SmallVector<TrieNode<AssociatedData> *, 4> Callees; + + /// Additional parameterized data on each node. + AssociatedData ExtraData; +}; + +/// Merges together two TrieNodes with like function ids, aggregating their +/// callee lists and durations. The caller must provide storage where new merged +/// nodes can be allocated in the form of a linked list. +template <typename T, typename Callable> +TrieNode<T> * +mergeTrieNodes(const TrieNode<T> &Left, const TrieNode<T> &Right, + /*Non-deduced pointer type for nullptr compatibility*/ + typename std::remove_reference<TrieNode<T> *>::type NewParent, + std::forward_list<TrieNode<T>> &NodeStore, + Callable &&MergeCallable) { + llvm::function_ref<T(const T &, const T &)> MergeFn( + std::forward<Callable>(MergeCallable)); + assert(Left.FuncId == Right.FuncId); + NodeStore.push_front(TrieNode<T>{ + Left.FuncId, NewParent, {}, MergeFn(Left.ExtraData, Right.ExtraData)}); + auto I = NodeStore.begin(); + auto *Node = &*I; + + // Build a map of callees from the left side. + llvm::DenseMap<int32_t, TrieNode<T> *> LeftCalleesByFuncId; + for (auto *Callee : Left.Callees) { + LeftCalleesByFuncId[Callee->FuncId] = Callee; + } + + // Iterate through the right side, either merging with the map values or + // directly adding to the Callees vector. The iteration also removes any + // merged values from the left side map. + // TODO: Unroll into iterative and explicit stack for efficiency. + for (auto *Callee : Right.Callees) { + auto iter = LeftCalleesByFuncId.find(Callee->FuncId); + if (iter != LeftCalleesByFuncId.end()) { + Node->Callees.push_back( + mergeTrieNodes(*(iter->second), *Callee, Node, NodeStore, MergeFn)); + LeftCalleesByFuncId.erase(iter); + } else { + Node->Callees.push_back(Callee); + } + } + + // Add any callees that weren't found in the right side. + for (auto MapPairIter : LeftCalleesByFuncId) { + Node->Callees.push_back(MapPairIter.second); + } + + return Node; +} + +#endif // LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H diff --git a/tools/llvm-xray/xray-converter.cc b/tools/llvm-xray/xray-converter.cc index f1aec65bc675..aa0da55207b3 100644 --- a/tools/llvm-xray/xray-converter.cc +++ b/tools/llvm-xray/xray-converter.cc @@ -12,10 +12,12 @@ //===----------------------------------------------------------------------===// #include "xray-converter.h" +#include "trie-node.h" #include "xray-registry.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" @@ -32,11 +34,14 @@ static cl::SubCommand Convert("convert", "Trace Format Conversion"); static cl::opt<std::string> ConvertInput(cl::Positional, cl::desc("<xray log file>"), cl::Required, cl::sub(Convert)); -enum class ConvertFormats { BINARY, YAML }; +enum class ConvertFormats { BINARY, YAML, CHROME_TRACE_EVENT }; static cl::opt<ConvertFormats> ConvertOutputFormat( "output-format", cl::desc("output format"), cl::values(clEnumValN(ConvertFormats::BINARY, "raw", "output in binary"), - clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml")), + clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml"), + clEnumValN(ConvertFormats::CHROME_TRACE_EVENT, "trace_event", + "Output in chrome's trace event format. " + "May be visualized with the Catapult trace viewer.")), cl::sub(Convert)); static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat), cl::desc("Alias for -output-format"), @@ -142,6 +147,192 @@ void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) { } } +namespace { + +// A structure that allows building a dictionary of stack ids for the Chrome +// trace event format. +struct StackIdData { + // Each Stack of function calls has a unique ID. + unsigned id; + + // Bookkeeping so that IDs can be maintained uniquely across threads. + // Traversal keeps sibling pointers to other threads stacks. This is helpful + // to determine when a thread encounters a new stack and should assign a new + // unique ID. + SmallVector<TrieNode<StackIdData> *, 4> siblings; +}; + +using StackTrieNode = TrieNode<StackIdData>; + +// A helper function to find the sibling nodes for an encountered function in a +// thread of execution. Relies on the invariant that each time a new node is +// traversed in a thread, sibling bidirectional pointers are maintained. +SmallVector<StackTrieNode *, 4> +findSiblings(StackTrieNode *parent, int32_t FnId, uint32_t TId, + const DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> + &StackRootsByThreadId) { + + SmallVector<StackTrieNode *, 4> Siblings{}; + + if (parent == nullptr) { + for (auto map_iter : StackRootsByThreadId) { + // Only look for siblings in other threads. + if (map_iter.first != TId) + for (auto node_iter : map_iter.second) { + if (node_iter->FuncId == FnId) + Siblings.push_back(node_iter); + } + } + return Siblings; + } + + for (auto *ParentSibling : parent->ExtraData.siblings) + for (auto node_iter : ParentSibling->Callees) + if (node_iter->FuncId == FnId) + Siblings.push_back(node_iter); + + return Siblings; +} + +// Given a function being invoked in a thread with id TId, finds and returns the +// StackTrie representing the function call stack. If no node exists, creates +// the node. Assigns unique IDs to stacks newly encountered among all threads +// and keeps sibling links up to when creating new nodes. +StackTrieNode *findOrCreateStackNode( + StackTrieNode *Parent, int32_t FuncId, uint32_t TId, + DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> &StackRootsByThreadId, + DenseMap<unsigned, StackTrieNode *> &StacksByStackId, unsigned *id_counter, + std::forward_list<StackTrieNode> &NodeStore) { + SmallVector<StackTrieNode *, 4> &ParentCallees = + Parent == nullptr ? StackRootsByThreadId[TId] : Parent->Callees; + auto match = find_if(ParentCallees, [FuncId](StackTrieNode *ParentCallee) { + return FuncId == ParentCallee->FuncId; + }); + if (match != ParentCallees.end()) + return *match; + + SmallVector<StackTrieNode *, 4> siblings = + findSiblings(Parent, FuncId, TId, StackRootsByThreadId); + if (siblings.empty()) { + NodeStore.push_front({FuncId, Parent, {}, {(*id_counter)++, {}}}); + StackTrieNode *CurrentStack = &NodeStore.front(); + StacksByStackId[*id_counter - 1] = CurrentStack; + ParentCallees.push_back(CurrentStack); + return CurrentStack; + } + unsigned stack_id = siblings[0]->ExtraData.id; + NodeStore.push_front({FuncId, Parent, {}, {stack_id, std::move(siblings)}}); + StackTrieNode *CurrentStack = &NodeStore.front(); + for (auto *sibling : CurrentStack->ExtraData.siblings) + sibling->ExtraData.siblings.push_back(CurrentStack); + ParentCallees.push_back(CurrentStack); + return CurrentStack; +} + +void writeTraceViewerRecord(raw_ostream &OS, int32_t FuncId, uint32_t TId, + bool Symbolize, + const FuncIdConversionHelper &FuncIdHelper, + double EventTimestampUs, + const StackTrieNode &StackCursor, + StringRef FunctionPhenotype) { + OS << " "; + OS << llvm::formatv( + R"({ "name" : "{0}", "ph" : "{1}", "tid" : "{2}", "pid" : "1", )" + R"("ts" : "{3:f3}", "sf" : "{4}" })", + (Symbolize ? FuncIdHelper.SymbolOrNumber(FuncId) + : llvm::to_string(FuncId)), + FunctionPhenotype, TId, EventTimestampUs, StackCursor.ExtraData.id); +} + +} // namespace + +void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records, + raw_ostream &OS) { + const auto &FH = Records.getFileHeader(); + auto CycleFreq = FH.CycleFrequency; + + unsigned id_counter = 0; + + OS << "{\n \"traceEvents\": ["; + DenseMap<uint32_t, StackTrieNode *> StackCursorByThreadId{}; + DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> StackRootsByThreadId{}; + DenseMap<unsigned, StackTrieNode *> StacksByStackId{}; + std::forward_list<StackTrieNode> NodeStore{}; + int loop_count = 0; + for (const auto &R : Records) { + if (loop_count++ == 0) + OS << "\n"; + else + OS << ",\n"; + + // Chrome trace event format always wants data in micros. + // CyclesPerMicro = CycleHertz / 10^6 + // TSC / CyclesPerMicro == TSC * 10^6 / CycleHertz == MicroTimestamp + // Could lose some precision here by converting the TSC to a double to + // multiply by the period in micros. 52 bit mantissa is a good start though. + // TODO: Make feature request to Chrome Trace viewer to accept ticks and a + // frequency or do some more involved calculation to avoid dangers of + // conversion. + double EventTimestampUs = double(1000000) / CycleFreq * double(R.TSC); + StackTrieNode *&StackCursor = StackCursorByThreadId[R.TId]; + switch (R.Type) { + case RecordTypes::ENTER: + case RecordTypes::ENTER_ARG: + StackCursor = findOrCreateStackNode(StackCursor, R.FuncId, R.TId, + StackRootsByThreadId, StacksByStackId, + &id_counter, NodeStore); + // Each record is represented as a json dictionary with function name, + // type of B for begin or E for end, thread id, process id (faked), + // timestamp in microseconds, and a stack frame id. The ids are logged + // in an id dictionary after the events. + writeTraceViewerRecord(OS, R.FuncId, R.TId, Symbolize, FuncIdHelper, + EventTimestampUs, *StackCursor, "B"); + break; + case RecordTypes::EXIT: + case RecordTypes::TAIL_EXIT: + // No entries to record end for. + if (StackCursor == nullptr) + break; + // Should we emit an END record anyway or account this condition? + // (And/Or in loop termination below) + StackTrieNode *PreviousCursor = nullptr; + do { + writeTraceViewerRecord(OS, StackCursor->FuncId, R.TId, Symbolize, + FuncIdHelper, EventTimestampUs, *StackCursor, + "E"); + PreviousCursor = StackCursor; + StackCursor = StackCursor->Parent; + } while (PreviousCursor->FuncId != R.FuncId && StackCursor != nullptr); + break; + } + } + OS << "\n ],\n"; // Close the Trace Events array. + OS << " " + << "\"displayTimeUnit\": \"ns\",\n"; + + // The stackFrames dictionary substantially reduces size of the output file by + // avoiding repeating the entire call stack of function names for each entry. + OS << R"( "stackFrames": {)"; + int stack_frame_count = 0; + for (auto map_iter : StacksByStackId) { + if (stack_frame_count++ == 0) + OS << "\n"; + else + OS << ",\n"; + OS << " "; + OS << llvm::formatv( + R"("{0}" : { "name" : "{1}")", map_iter.first, + (Symbolize ? FuncIdHelper.SymbolOrNumber(map_iter.second->FuncId) + : llvm::to_string(map_iter.second->FuncId))); + if (map_iter.second->Parent != nullptr) + OS << llvm::formatv(R"(, "parent": "{0}")", + map_iter.second->Parent->ExtraData.id); + OS << " }"; + } + OS << "\n }\n"; // Close the stack frames map. + OS << "}\n"; // Close the JSON entry. +} + namespace llvm { namespace xray { @@ -191,6 +382,9 @@ static CommandRegistration Unused(&Convert, []() -> Error { case ConvertFormats::BINARY: TC.exportAsRAWv1(T, OS); break; + case ConvertFormats::CHROME_TRACE_EVENT: + TC.exportAsChromeTraceEventFormat(T, OS); + break; } return Error::success(); }); diff --git a/tools/llvm-xray/xray-converter.h b/tools/llvm-xray/xray-converter.h index fa0d5e132f14..5f0a3ee298eb 100644 --- a/tools/llvm-xray/xray-converter.h +++ b/tools/llvm-xray/xray-converter.h @@ -15,8 +15,8 @@ #define LLVM_TOOLS_LLVM_XRAY_XRAY_CONVERTER_H #include "func-id-helper.h" -#include "llvm/XRay/XRayRecord.h" #include "llvm/XRay/Trace.h" +#include "llvm/XRay/XRayRecord.h" namespace llvm { namespace xray { @@ -31,6 +31,11 @@ public: void exportAsYAML(const Trace &Records, raw_ostream &OS); void exportAsRAWv1(const Trace &Records, raw_ostream &OS); + + /// For this conversion, the Function records within each thread are expected + /// to be in sorted TSC order. The trace event format encodes stack traces, so + /// the linear history is essential for correct output. + void exportAsChromeTraceEventFormat(const Trace &Records, raw_ostream &OS); }; } // namespace xray diff --git a/tools/llvm-xray/xray-stacks.cc b/tools/llvm-xray/xray-stacks.cc index fd5df82e093d..9474de047990 100644 --- a/tools/llvm-xray/xray-stacks.cc +++ b/tools/llvm-xray/xray-stacks.cc @@ -19,6 +19,7 @@ #include <numeric> #include "func-id-helper.h" +#include "trie-node.h" #include "xray-registry.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" @@ -255,96 +256,61 @@ private: /// maintain an index of unique functions, and provide a means of iterating /// through all the instrumented call stacks which we know about. -struct TrieNode { - int32_t FuncId; - TrieNode *Parent; - SmallVector<TrieNode *, 4> Callees; - // Separate durations depending on whether the node is the deepest node in the - // stack. - SmallVector<int64_t, 4> TerminalDurations; - SmallVector<int64_t, 4> IntermediateDurations; +struct StackDuration { + llvm::SmallVector<int64_t, 4> TerminalDurations; + llvm::SmallVector<int64_t, 4> IntermediateDurations; }; -/// Merges together two TrieNodes with like function ids, aggregating their -/// callee lists and durations. The caller must provide storage where new merged -/// nodes can be allocated in the form of a linked list. -TrieNode *mergeTrieNodes(const TrieNode &Left, const TrieNode &Right, - TrieNode *NewParent, - std::forward_list<TrieNode> &NodeStore) { - assert(Left.FuncId == Right.FuncId); - NodeStore.push_front(TrieNode{Left.FuncId, NewParent, {}, {}, {}}); - auto I = NodeStore.begin(); - auto *Node = &*I; - - // Build a map of callees from the left side. - DenseMap<int32_t, TrieNode *> LeftCalleesByFuncId; - for (auto *Callee : Left.Callees) { - LeftCalleesByFuncId[Callee->FuncId] = Callee; - } - - // Iterate through the right side, either merging with the map values or - // directly adding to the Callees vector. The iteration also removes any - // merged values from the left side map. - for (auto *Callee : Right.Callees) { - auto iter = LeftCalleesByFuncId.find(Callee->FuncId); - if (iter != LeftCalleesByFuncId.end()) { - Node->Callees.push_back( - mergeTrieNodes(*(iter->second), *Callee, Node, NodeStore)); - LeftCalleesByFuncId.erase(iter); - } else { - Node->Callees.push_back(Callee); - } - } - - // Add any callees that weren't found in the right side. - for (auto MapPairIter : LeftCalleesByFuncId) { - Node->Callees.push_back(MapPairIter.second); - } - +StackDuration mergeStackDuration(const StackDuration &Left, + const StackDuration &Right) { + StackDuration Data{}; + Data.TerminalDurations.reserve(Left.TerminalDurations.size() + + Right.TerminalDurations.size()); + Data.IntermediateDurations.reserve(Left.IntermediateDurations.size() + + Right.IntermediateDurations.size()); // Aggregate the durations. - for (auto duration : Left.TerminalDurations) { - Node->TerminalDurations.push_back(duration); - } - for (auto duration : Right.TerminalDurations) { - Node->TerminalDurations.push_back(duration); - } - for (auto duration : Left.IntermediateDurations) { - Node->IntermediateDurations.push_back(duration); - } - for (auto duration : Right.IntermediateDurations) { - Node->IntermediateDurations.push_back(duration); - } - - return Node; + for (auto duration : Left.TerminalDurations) + Data.TerminalDurations.push_back(duration); + for (auto duration : Right.TerminalDurations) + Data.TerminalDurations.push_back(duration); + + for (auto duration : Left.IntermediateDurations) + Data.IntermediateDurations.push_back(duration); + for (auto duration : Right.IntermediateDurations) + Data.IntermediateDurations.push_back(duration); + return Data; } +using StackTrieNode = TrieNode<StackDuration>; + template <AggregationType AggType> -std::size_t GetValueForStack(const TrieNode *Node); +std::size_t GetValueForStack(const StackTrieNode *Node); // When computing total time spent in a stack, we're adding the timings from // its callees and the timings from when it was a leaf. template <> std::size_t -GetValueForStack<AggregationType::TOTAL_TIME>(const TrieNode *Node) { - auto TopSum = std::accumulate(Node->TerminalDurations.begin(), - Node->TerminalDurations.end(), 0uLL); - return std::accumulate(Node->IntermediateDurations.begin(), - Node->IntermediateDurations.end(), TopSum); +GetValueForStack<AggregationType::TOTAL_TIME>(const StackTrieNode *Node) { + auto TopSum = std::accumulate(Node->ExtraData.TerminalDurations.begin(), + Node->ExtraData.TerminalDurations.end(), 0uLL); + return std::accumulate(Node->ExtraData.IntermediateDurations.begin(), + Node->ExtraData.IntermediateDurations.end(), TopSum); } // Calculates how many times a function was invoked. // TODO: Hook up option to produce stacks template <> std::size_t -GetValueForStack<AggregationType::INVOCATION_COUNT>(const TrieNode *Node) { - return Node->TerminalDurations.size() + Node->IntermediateDurations.size(); +GetValueForStack<AggregationType::INVOCATION_COUNT>(const StackTrieNode *Node) { + return Node->ExtraData.TerminalDurations.size() + + Node->ExtraData.IntermediateDurations.size(); } // Make sure there are implementations for each enum value. template <AggregationType T> struct DependentFalseType : std::false_type {}; template <AggregationType AggType> -std::size_t GetValueForStack(const TrieNode *Node) { +std::size_t GetValueForStack(const StackTrieNode *Node) { static_assert(DependentFalseType<AggType>::value, "No implementation found for aggregation type provided."); return 0; @@ -353,21 +319,21 @@ std::size_t GetValueForStack(const TrieNode *Node) { class StackTrie { // Avoid the magic number of 4 propagated through the code with an alias. // We use this SmallVector to track the root nodes in a call graph. - using RootVector = SmallVector<TrieNode *, 4>; + using RootVector = SmallVector<StackTrieNode *, 4>; // We maintain pointers to the roots of the tries we see. DenseMap<uint32_t, RootVector> Roots; // We make sure all the nodes are accounted for in this list. - std::forward_list<TrieNode> NodeStore; + std::forward_list<StackTrieNode> NodeStore; // A map of thread ids to pairs call stack trie nodes and their start times. - DenseMap<uint32_t, SmallVector<std::pair<TrieNode *, uint64_t>, 8>> + DenseMap<uint32_t, SmallVector<std::pair<StackTrieNode *, uint64_t>, 8>> ThreadStackMap; - TrieNode *createTrieNode(uint32_t ThreadId, int32_t FuncId, - TrieNode *Parent) { - NodeStore.push_front(TrieNode{FuncId, Parent, {}, {}, {}}); + StackTrieNode *createTrieNode(uint32_t ThreadId, int32_t FuncId, + StackTrieNode *Parent) { + NodeStore.push_front(StackTrieNode{FuncId, Parent, {}, {{}, {}}}); auto I = NodeStore.begin(); auto *Node = &*I; if (!Parent) @@ -375,10 +341,10 @@ class StackTrie { return Node; } - TrieNode *findRootNode(uint32_t ThreadId, int32_t FuncId) { + StackTrieNode *findRootNode(uint32_t ThreadId, int32_t FuncId) { const auto &RootsByThread = Roots[ThreadId]; auto I = find_if(RootsByThread, - [&](TrieNode *N) { return N->FuncId == FuncId; }); + [&](StackTrieNode *N) { return N->FuncId == FuncId; }); return (I == RootsByThread.end()) ? nullptr : *I; } @@ -416,7 +382,7 @@ public: auto &Top = TS.back(); auto I = find_if(Top.first->Callees, - [&](TrieNode *N) { return N->FuncId == R.FuncId; }); + [&](StackTrieNode *N) { return N->FuncId == R.FuncId; }); if (I == Top.first->Callees.end()) { // We didn't find the callee in the stack trie, so we're going to // add to the stack then set up the pointers properly. @@ -447,8 +413,8 @@ public: return AccountRecordStatus::ENTRY_NOT_FOUND; } - auto FunctionEntryMatch = - find_if(reverse(TS), [&](const std::pair<TrieNode *, uint64_t> &E) { + auto FunctionEntryMatch = find_if( + reverse(TS), [&](const std::pair<StackTrieNode *, uint64_t> &E) { return E.first->FuncId == R.FuncId; }); auto status = AccountRecordStatus::OK; @@ -461,14 +427,14 @@ public: } auto I = FunctionEntryMatch.base(); for (auto &E : make_range(I, TS.end() - 1)) - E.first->IntermediateDurations.push_back(std::max(E.second, R.TSC) - - std::min(E.second, R.TSC)); + E.first->ExtraData.IntermediateDurations.push_back( + std::max(E.second, R.TSC) - std::min(E.second, R.TSC)); auto &Deepest = TS.back(); if (wasLastRecordExit) - Deepest.first->IntermediateDurations.push_back( + Deepest.first->ExtraData.IntermediateDurations.push_back( std::max(Deepest.second, R.TSC) - std::min(Deepest.second, R.TSC)); else - Deepest.first->TerminalDurations.push_back( + Deepest.first->ExtraData.TerminalDurations.push_back( std::max(Deepest.second, R.TSC) - std::min(Deepest.second, R.TSC)); TS.erase(I, TS.end()); return status; @@ -479,11 +445,11 @@ public: bool isEmpty() const { return Roots.empty(); } - void printStack(raw_ostream &OS, const TrieNode *Top, + void printStack(raw_ostream &OS, const StackTrieNode *Top, FuncIdConversionHelper &FN) { // Traverse the pointers up to the parent, noting the sums, then print // in reverse order (callers at top, callees down bottom). - SmallVector<const TrieNode *, 8> CurrentStack; + SmallVector<const StackTrieNode *, 8> CurrentStack; for (auto *F = Top; F != nullptr; F = F->Parent) CurrentStack.push_back(F); int Level = 0; @@ -491,21 +457,22 @@ public: "count", "sum"); for (auto *F : reverse(make_range(CurrentStack.begin() + 1, CurrentStack.end()))) { - auto Sum = std::accumulate(F->IntermediateDurations.begin(), - F->IntermediateDurations.end(), 0LL); + auto Sum = std::accumulate(F->ExtraData.IntermediateDurations.begin(), + F->ExtraData.IntermediateDurations.end(), 0LL); auto FuncId = FN.SymbolOrNumber(F->FuncId); OS << formatv("#{0,-4} {1,-60} {2,+12} {3,+16}\n", Level++, FuncId.size() > 60 ? FuncId.substr(0, 57) + "..." : FuncId, - F->IntermediateDurations.size(), Sum); + F->ExtraData.IntermediateDurations.size(), Sum); } auto *Leaf = *CurrentStack.begin(); - auto LeafSum = std::accumulate(Leaf->TerminalDurations.begin(), - Leaf->TerminalDurations.end(), 0LL); + auto LeafSum = + std::accumulate(Leaf->ExtraData.TerminalDurations.begin(), + Leaf->ExtraData.TerminalDurations.end(), 0LL); auto LeafFuncId = FN.SymbolOrNumber(Leaf->FuncId); OS << formatv("#{0,-4} {1,-60} {2,+12} {3,+16}\n", Level++, LeafFuncId.size() > 60 ? LeafFuncId.substr(0, 57) + "..." : LeafFuncId, - Leaf->TerminalDurations.size(), LeafSum); + Leaf->ExtraData.TerminalDurations.size(), LeafSum); OS << "\n"; } @@ -552,20 +519,20 @@ public: /// Creates a merged list of Tries for unique stacks that disregards their /// thread IDs. - RootVector mergeAcrossThreads(std::forward_list<TrieNode> &NodeStore) { + RootVector mergeAcrossThreads(std::forward_list<StackTrieNode> &NodeStore) { RootVector MergedByThreadRoots; for (auto MapIter : Roots) { const auto &RootNodeVector = MapIter.second; for (auto *Node : RootNodeVector) { auto MaybeFoundIter = - find_if(MergedByThreadRoots, [Node](TrieNode *elem) { + find_if(MergedByThreadRoots, [Node](StackTrieNode *elem) { return Node->FuncId == elem->FuncId; }); if (MaybeFoundIter == MergedByThreadRoots.end()) { MergedByThreadRoots.push_back(Node); } else { - MergedByThreadRoots.push_back( - mergeTrieNodes(**MaybeFoundIter, *Node, nullptr, NodeStore)); + MergedByThreadRoots.push_back(mergeTrieNodes( + **MaybeFoundIter, *Node, nullptr, NodeStore, mergeStackDuration)); MergedByThreadRoots.erase(MaybeFoundIter); } } @@ -577,7 +544,7 @@ public: template <AggregationType AggType> void printAllAggregatingThreads(raw_ostream &OS, FuncIdConversionHelper &FN, StackOutputFormat format) { - std::forward_list<TrieNode> AggregatedNodeStore; + std::forward_list<StackTrieNode> AggregatedNodeStore; RootVector MergedByThreadRoots = mergeAcrossThreads(AggregatedNodeStore); bool reportThreadId = false; printAll<AggType>(OS, FN, MergedByThreadRoots, @@ -586,7 +553,7 @@ public: /// Merges the trie by thread id before printing top stacks. void printAggregatingThreads(raw_ostream &OS, FuncIdConversionHelper &FN) { - std::forward_list<TrieNode> AggregatedNodeStore; + std::forward_list<StackTrieNode> AggregatedNodeStore; RootVector MergedByThreadRoots = mergeAcrossThreads(AggregatedNodeStore); print(OS, FN, MergedByThreadRoots); } @@ -595,7 +562,7 @@ public: template <AggregationType AggType> void printAll(raw_ostream &OS, FuncIdConversionHelper &FN, RootVector RootValues, uint32_t ThreadId, bool ReportThread) { - SmallVector<const TrieNode *, 16> S; + SmallVector<const StackTrieNode *, 16> S; for (const auto *N : RootValues) { S.clear(); S.push_back(N); @@ -616,10 +583,10 @@ public: template <AggregationType AggType> void printSingleStack(raw_ostream &OS, FuncIdConversionHelper &Converter, bool ReportThread, uint32_t ThreadId, - const TrieNode *Node) { + const StackTrieNode *Node) { if (ReportThread) OS << "thread_" << ThreadId << ";"; - SmallVector<const TrieNode *, 5> lineage{}; + SmallVector<const StackTrieNode *, 5> lineage{}; lineage.push_back(Node); while (lineage.back()->Parent != nullptr) lineage.push_back(lineage.back()->Parent); @@ -639,15 +606,17 @@ public: // - Total number of unique stacks // - Top 10 stacks by count // - Top 10 stacks by aggregate duration - SmallVector<std::pair<const TrieNode *, uint64_t>, 11> TopStacksByCount; - SmallVector<std::pair<const TrieNode *, uint64_t>, 11> TopStacksBySum; - auto greater_second = [](const std::pair<const TrieNode *, uint64_t> &A, - const std::pair<const TrieNode *, uint64_t> &B) { - return A.second > B.second; - }; + SmallVector<std::pair<const StackTrieNode *, uint64_t>, 11> + TopStacksByCount; + SmallVector<std::pair<const StackTrieNode *, uint64_t>, 11> TopStacksBySum; + auto greater_second = + [](const std::pair<const StackTrieNode *, uint64_t> &A, + const std::pair<const StackTrieNode *, uint64_t> &B) { + return A.second > B.second; + }; uint64_t UniqueStacks = 0; for (const auto *N : RootValues) { - SmallVector<const TrieNode *, 16> S; + SmallVector<const StackTrieNode *, 16> S; S.emplace_back(N); while (!S.empty()) { @@ -655,10 +624,11 @@ public: // We only start printing the stack (by walking up the parent pointers) // when we get to a leaf function. - if (!Top->TerminalDurations.empty()) { + if (!Top->ExtraData.TerminalDurations.empty()) { ++UniqueStacks; - auto TopSum = std::accumulate(Top->TerminalDurations.begin(), - Top->TerminalDurations.end(), 0uLL); + auto TopSum = + std::accumulate(Top->ExtraData.TerminalDurations.begin(), + Top->ExtraData.TerminalDurations.end(), 0uLL); { auto E = std::make_pair(Top, TopSum); TopStacksBySum.insert(std::lower_bound(TopStacksBySum.begin(), @@ -669,7 +639,8 @@ public: TopStacksBySum.pop_back(); } { - auto E = std::make_pair(Top, Top->TerminalDurations.size()); + auto E = + std::make_pair(Top, Top->ExtraData.TerminalDurations.size()); TopStacksByCount.insert(std::lower_bound(TopStacksByCount.begin(), TopStacksByCount.end(), E, greater_second), diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index e2fdfe82b8c6..0371cd0372f4 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -391,6 +391,7 @@ int main(int argc, char **argv) { initializeTarget(Registry); // For codegen passes, only passes that do IR to IR transformation are // supported. + initializeExpandMemCmpPassPass(Registry); initializeScalarizeMaskedMemIntrinPass(Registry); initializeCodeGenPreparePass(Registry); initializeAtomicExpandPass(Registry); |