summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/dsymutil/DwarfLinker.cpp6
-rw-r--r--tools/dsymutil/dsymutil.cpp13
-rw-r--r--tools/llvm-ar/CMakeLists.txt6
-rw-r--r--tools/llvm-ar/llvm-ar.cpp20
-rw-r--r--tools/llvm-cfi-verify/CMakeLists.txt2
-rw-r--r--tools/llvm-cfi-verify/LLVMBuild.txt2
-rw-r--r--tools/llvm-cfi-verify/lib/CMakeLists.txt4
-rw-r--r--tools/llvm-cfi-verify/lib/FileAnalysis.cpp49
-rw-r--r--tools/llvm-cfi-verify/lib/FileAnalysis.h9
-rw-r--r--tools/llvm-cfi-verify/lib/LLVMBuild.txt2
-rw-r--r--tools/llvm-cfi-verify/llvm-cfi-verify.cpp135
-rw-r--r--tools/llvm-cov/gcov.cpp2
-rw-r--r--tools/llvm-cvtres/llvm-cvtres.cpp2
-rw-r--r--tools/llvm-cxxdump/llvm-cxxdump.cpp15
-rw-r--r--tools/llvm-cxxfilt/CMakeLists.txt4
-rw-r--r--tools/llvm-dwp/CMakeLists.txt4
-rw-r--r--tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp6
-rw-r--r--tools/llvm-mcmarkup/llvm-mcmarkup.cpp13
-rw-r--r--tools/llvm-mt/llvm-mt.cpp4
-rw-r--r--tools/llvm-nm/CMakeLists.txt4
-rw-r--r--tools/llvm-nm/llvm-nm.cpp13
-rw-r--r--tools/llvm-objcopy/CMakeLists.txt4
-rw-r--r--tools/llvm-objcopy/Object.cpp20
-rw-r--r--tools/llvm-objcopy/Object.h1
-rw-r--r--tools/llvm-objcopy/llvm-objcopy.cpp81
-rw-r--r--tools/llvm-objdump/CMakeLists.txt4
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp30
-rw-r--r--tools/llvm-pdbutil/llvm-pdbutil.cpp25
-rw-r--r--tools/llvm-readobj/CMakeLists.txt4
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp15
-rw-r--r--tools/llvm-size/CMakeLists.txt4
-rw-r--r--tools/llvm-size/llvm-size.cpp15
-rw-r--r--tools/llvm-strings/CMakeLists.txt3
-rw-r--r--tools/llvm-symbolizer/CMakeLists.txt4
-rw-r--r--tools/llvm-xray/trie-node.h92
-rw-r--r--tools/llvm-xray/xray-converter.cc198
-rw-r--r--tools/llvm-xray/xray-converter.h7
-rw-r--r--tools/llvm-xray/xray-stacks.cc191
-rw-r--r--tools/opt/opt.cpp1
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);