Importing rustc-1.78.0
Bug: 333887339
Test: ./build.py --lto=thin
Change-Id: I70466db5e03cbd71cc5874ebae0a6d6c9fece91c
diff --git a/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt b/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt
index 6df49d7..60fc1bd 100644
--- a/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt
@@ -10,7 +10,7 @@
endif()
endif()
-if(WIN32 OR CYGWIN)
+if(WIN32 OR CYGWIN OR ZOS)
set(LLVM_LINK_COMPONENTS Core Support)
endif()
diff --git a/src/llvm-project/llvm/tools/bugpoint/BugDriver.h b/src/llvm-project/llvm/tools/bugpoint/BugDriver.h
index 9fb0880..e3117ec 100644
--- a/src/llvm-project/llvm/tools/bugpoint/BugDriver.h
+++ b/src/llvm-project/llvm/tools/bugpoint/BugDriver.h
@@ -25,7 +25,6 @@
namespace llvm {
-class PassInfo;
class Module;
class GlobalVariable;
class Function;
diff --git a/src/llvm-project/llvm/tools/bugpoint/ExecutionDriver.cpp b/src/llvm-project/llvm/tools/bugpoint/ExecutionDriver.cpp
index 2b06e8f..18187ad 100644
--- a/src/llvm-project/llvm/tools/bugpoint/ExecutionDriver.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/ExecutionDriver.cpp
@@ -299,7 +299,7 @@
<< "!\n";
exit(1);
}
- BitcodeFile = std::string(UniqueFilename.str());
+ BitcodeFile = std::string(UniqueFilename);
if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) {
errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile
@@ -324,7 +324,7 @@
<< "\n";
exit(1);
}
- OutputFile = std::string(UniqueFile.str());
+ OutputFile = std::string(UniqueFile);
// Figure out which shared objects to run, if any.
std::vector<std::string> SharedObjs(AdditionalSOs);
diff --git a/src/llvm-project/llvm/tools/bugpoint/Miscompilation.cpp b/src/llvm-project/llvm/tools/bugpoint/Miscompilation.cpp
index 3882194..22806ba 100644
--- a/src/llvm-project/llvm/tools/bugpoint/Miscompilation.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/Miscompilation.cpp
@@ -830,8 +830,8 @@
// Add the resolver to the Safe module.
// Prototype: void *getPointerToNamedFunction(const char* Name)
FunctionCallee resolverFunc = Safe->getOrInsertFunction(
- "getPointerToNamedFunction", Type::getInt8PtrTy(Safe->getContext()),
- Type::getInt8PtrTy(Safe->getContext()));
+ "getPointerToNamedFunction", PointerType::getUnqual(Safe->getContext()),
+ PointerType::getUnqual(Safe->getContext()));
// Use the function we just added to get addresses of functions we need.
for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
@@ -956,8 +956,7 @@
<< "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
- if (BD.writeProgramToFile(std::string(TestModuleBC.str()), TestModuleFD,
- *Test)) {
+ if (BD.writeProgramToFile(std::string(TestModuleBC), TestModuleFD, *Test)) {
errs() << "Error writing bitcode to `" << TestModuleBC.str()
<< "'\nExiting.";
exit(1);
@@ -976,8 +975,7 @@
exit(1);
}
- if (BD.writeProgramToFile(std::string(SafeModuleBC.str()), SafeModuleFD,
- *Safe)) {
+ if (BD.writeProgramToFile(std::string(SafeModuleBC), SafeModuleFD, *Safe)) {
errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting.";
exit(1);
}
@@ -985,7 +983,7 @@
FileRemover SafeModuleBCRemover(SafeModuleBC.str(), !SaveTemps);
Expected<std::string> SharedObject =
- BD.compileSharedObject(std::string(SafeModuleBC.str()));
+ BD.compileSharedObject(std::string(SafeModuleBC));
if (Error E = SharedObject.takeError())
return std::move(E);
@@ -994,7 +992,7 @@
// Run the code generator on the `Test' code, loading the shared library.
// The function returns whether or not the new output differs from reference.
Expected<bool> Result = BD.diffProgram(
- BD.getProgram(), std::string(TestModuleBC.str()), *SharedObject, false);
+ BD.getProgram(), std::string(TestModuleBC), *SharedObject, false);
if (Error E = Result.takeError())
return std::move(E);
@@ -1051,8 +1049,7 @@
exit(1);
}
- if (writeProgramToFile(std::string(TestModuleBC.str()), TestModuleFD,
- *ToCodeGen)) {
+ if (writeProgramToFile(std::string(TestModuleBC), TestModuleFD, *ToCodeGen)) {
errs() << "Error writing bitcode to `" << TestModuleBC << "'\nExiting.";
exit(1);
}
@@ -1068,13 +1065,13 @@
exit(1);
}
- if (writeProgramToFile(std::string(SafeModuleBC.str()), SafeModuleFD,
+ if (writeProgramToFile(std::string(SafeModuleBC), SafeModuleFD,
*ToNotCodeGen)) {
errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting.";
exit(1);
}
Expected<std::string> SharedObject =
- compileSharedObject(std::string(SafeModuleBC.str()));
+ compileSharedObject(std::string(SafeModuleBC));
if (Error E = SharedObject.takeError())
return E;
diff --git a/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp b/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp
index f7239f5..ce32459 100644
--- a/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp
@@ -141,7 +141,7 @@
<< ": Error making unique filename: " << EC.message() << "\n";
return true;
}
- OutputFilename = std::string(UniqueFilename.str());
+ OutputFilename = std::string(UniqueFilename);
// set up the input file name
Expected<sys::fs::TempFile> Temp =
diff --git a/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp b/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
index c6733ae..e45c89b 100644
--- a/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
@@ -442,7 +442,7 @@
errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
- OutputAsmFile = std::string(UniqueFile.str());
+ OutputAsmFile = std::string(UniqueFile);
std::vector<StringRef> LLCArgs;
LLCArgs.push_back(LLCPath);
@@ -772,7 +772,7 @@
errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
- OutputFile = std::string(UniqueFilename.str());
+ OutputFile = std::string(UniqueFilename);
std::vector<StringRef> CCArgs;
diff --git a/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp b/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp
index d8293f7..646fe4f 100644
--- a/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp
@@ -26,7 +26,7 @@
return {Archive, Object};
}
-static bool isArchive(StringRef Filename) { return Filename.endswith(")"); }
+static bool isArchive(StringRef Filename) { return Filename.ends_with(")"); }
static std::vector<MemoryBufferRef>
getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
@@ -182,7 +182,7 @@
for (const auto &Archive : Archives) {
Error Err = Error::success();
- for (auto Child : Archive->children(Err)) {
+ for (const auto &Child : Archive->children(Err)) {
if (auto NameOrErr = Child.getName()) {
if (*NameOrErr == ObjectFilename) {
auto ModTimeOrErr = Child.getLastModified();
@@ -238,6 +238,7 @@
if (isArchive(Filename)) {
StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
std::lock_guard<std::mutex> Lock(ArchiveCacheMutex);
+ ArchiveRefCounter[ArchiveFilename]++;
if (ArchiveCache.count(ArchiveFilename)) {
return ArchiveCache[ArchiveFilename]->getObjectEntry(Filename, Timestamp,
Verbose);
@@ -258,6 +259,7 @@
// If this is an object, we might have it cached. If not we'll have to load
// it from the file system and cache it now.
std::lock_guard<std::mutex> Lock(ObjectCacheMutex);
+ ObjectRefCounter[Filename]++;
if (!ObjectCache.count(Filename)) {
auto OE = std::make_unique<ObjectEntry>();
auto Err = OE->load(VFS, Filename, Timestamp, Verbose);
@@ -276,5 +278,24 @@
ObjectCache.clear();
}
+void BinaryHolder::eraseObjectEntry(StringRef Filename) {
+ if (Verbose)
+ WithColor::note() << "erasing '" << Filename << "' from cache\n";
+
+ if (isArchive(Filename)) {
+ StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
+ std::lock_guard<std::mutex> Lock(ArchiveCacheMutex);
+ ArchiveRefCounter[ArchiveFilename]--;
+ if (ArchiveRefCounter[ArchiveFilename] == 0)
+ ArchiveCache.erase(ArchiveFilename);
+ return;
+ }
+
+ std::lock_guard<std::mutex> Lock(ObjectCacheMutex);
+ ObjectRefCounter[Filename]--;
+ if (ObjectRefCounter[Filename] == 0)
+ ObjectCache.erase(Filename);
+}
+
} // namespace dsymutil
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.h b/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.h
index 84084c5..c4fc5a6 100644
--- a/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.h
+++ b/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.h
@@ -126,15 +126,18 @@
getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());
void clear();
+ void eraseObjectEntry(StringRef Filename);
private:
/// Cache of static archives. Objects that are part of a static archive are
/// stored under this object, rather than in the map below.
StringMap<std::unique_ptr<ArchiveEntry>> ArchiveCache;
+ StringMap<uint32_t> ArchiveRefCounter;
std::mutex ArchiveCacheMutex;
/// Object entries for objects that are not in a static archive.
StringMap<std::unique_ptr<ObjectEntry>> ObjectCache;
+ StringMap<uint32_t> ObjectRefCounter;
std::mutex ObjectCacheMutex;
/// Virtual File System instance.
diff --git a/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt b/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt
index 3cb88a5..53f882e 100644
--- a/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt
@@ -10,6 +10,7 @@
CodeGen
CodeGenTypes
DWARFLinker
+ DWARFLinkerClassic
DWARFLinkerParallel
DebugInfoDWARF
MC
@@ -30,16 +31,18 @@
MachODebugMapParser.cpp
MachOUtils.cpp
Reproducer.cpp
+ RelocationMap.cpp
SymbolMap.cpp
DEPENDS
intrinsics_gen
${tablegen_deps}
DsymutilTableGen
+ GENERATE_DRIVER
)
-if(APPLE)
+if(APPLE AND NOT LLVM_TOOL_LLVM_DRIVER_BUILD)
target_link_libraries(dsymutil PRIVATE "-framework CoreFoundation")
-endif(APPLE)
+endif(APPLE AND NOT LLVM_TOOL_LLVM_DRIVER_BUILD)
# target_link_libraries(dsymutil PRIVATE ${LLVM_ATOMIC_LIB})
diff --git a/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp b/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp
index 5ae7217..8724b70 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp
@@ -11,7 +11,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Chrono.h"
@@ -46,6 +45,11 @@
bool DebugMapObject::addSymbol(StringRef Name,
std::optional<uint64_t> ObjectAddress,
uint64_t LinkedAddress, uint32_t Size) {
+ if (Symbols.count(Name)) {
+ // Symbol was previously added.
+ return true;
+ }
+
auto InsertResult = Symbols.insert(
std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
@@ -54,6 +58,12 @@
return InsertResult.second;
}
+void DebugMapObject::setRelocationMap(dsymutil::RelocationMap &RM) {
+ RelocMap.emplace(RM);
+}
+
+void DebugMapObject::setInstallName(StringRef IN) { InstallName.emplace(IN); }
+
void DebugMapObject::print(raw_ostream &OS) const {
OS << getObjectFilename() << ":\n";
// Sort the symbols in alphabetical order, like llvm-nm (and to get
@@ -159,8 +169,8 @@
std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
};
-void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
- mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
+void MappingTraits<std::pair<std::string, SymbolMapping>>::mapping(
+ IO &io, std::pair<std::string, SymbolMapping> &s) {
io.mapRequired("sym", s.first);
io.mapOptional("objAddr", s.second.ObjectAddress);
io.mapRequired("binAddr", s.second.BinaryAddress);
@@ -276,7 +286,13 @@
}
}
- dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
+ uint8_t Type = MachO::N_OSO;
+ if (Path.ends_with(".dylib")) {
+ // FIXME: find a more resilient way
+ Type = MachO::N_LIB;
+ }
+ dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), Type);
+
for (auto &Entry : Entries) {
auto &Mapping = Entry.second;
std::optional<uint64_t> ObjAddress;
diff --git a/src/llvm-project/llvm/tools/dsymutil/DebugMap.h b/src/llvm-project/llvm/tools/dsymutil/DebugMap.h
index 86cb88d..9c3a698 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DebugMap.h
+++ b/src/llvm-project/llvm/tools/dsymutil/DebugMap.h
@@ -21,6 +21,7 @@
#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
+#include "RelocationMap.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -134,22 +135,6 @@
/// linked binary for all the linked atoms in this object file.
class DebugMapObject {
public:
- struct SymbolMapping {
- std::optional<yaml::Hex64> ObjectAddress;
- yaml::Hex64 BinaryAddress;
- yaml::Hex32 Size;
-
- SymbolMapping(std::optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
- uint32_t Size)
- : BinaryAddress(BinaryAddress), Size(Size) {
- if (ObjectAddr)
- ObjectAddress = *ObjectAddr;
- }
-
- /// For YAML IO support
- SymbolMapping() = default;
- };
-
using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>;
using DebugMapEntry = StringMapEntry<SymbolMapping>;
@@ -182,6 +167,16 @@
}
const std::vector<std::string> &getWarnings() const { return Warnings; }
+ const std::optional<RelocationMap> &getRelocationMap() const {
+ return RelocMap;
+ }
+ void setRelocationMap(dsymutil::RelocationMap &RM);
+
+ const std::optional<std::string> &getInstallName() const {
+ return InstallName;
+ }
+ void setInstallName(StringRef IN);
+
void print(raw_ostream &OS) const;
#ifndef NDEBUG
void dump() const;
@@ -196,10 +191,13 @@
std::string Filename;
sys::TimePoint<std::chrono::seconds> Timestamp;
- StringMap<SymbolMapping> Symbols;
+ StringMap<struct SymbolMapping> Symbols;
DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
uint8_t Type;
+ std::optional<RelocationMap> RelocMap;
+ std::optional<std::string> InstallName;
+
std::vector<std::string> Warnings;
/// For YAMLIO support.
@@ -225,10 +223,8 @@
using namespace llvm::dsymutil;
-template <>
-struct MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>> {
- static void mapping(IO &io,
- std::pair<std::string, DebugMapObject::SymbolMapping> &s);
+template <> struct MappingTraits<std::pair<std::string, SymbolMapping>> {
+ static void mapping(IO &io, std::pair<std::string, SymbolMapping> &s);
static const bool flow = true;
};
@@ -237,12 +233,6 @@
static void mapping(IO &io, dsymutil::DebugMapObject &DMO);
};
-template <> struct ScalarTraits<Triple> {
- static void output(const Triple &val, void *, raw_ostream &out);
- static StringRef input(StringRef scalar, void *, Triple &value);
- static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
-};
-
template <>
struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> {
static size_t
diff --git a/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index 4b281d5..5ae5ecd 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -12,16 +12,11 @@
#include "MachOUtils.h"
#include "dsymutil.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Dwarf.h"
@@ -32,8 +27,9 @@
#include "llvm/CodeGen/DIE.h"
#include "llvm/CodeGen/NonRelocatableStringpool.h"
#include "llvm/Config/config.h"
-#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
-#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
+#include "llvm/DWARFLinker/Classic/DWARFLinker.h"
+#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
+#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -105,6 +101,8 @@
static mc::RegisterMCTargetOptionsFlags MOF;
+using namespace dwarf_linker;
+
namespace dsymutil {
static void dumpDIE(const DWARFDie *DIE, bool Verbose) {
@@ -123,16 +121,22 @@
/// specific \p DIE related to the warning.
void DwarfLinkerForBinary::reportWarning(Twine Warning, Twine Context,
const DWARFDie *DIE) const {
- std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
- warn(Warning, Context);
- dumpDIE(DIE, Options.Verbose);
+ // FIXME: implement warning logging which does not block other threads.
+ if (ErrorHandlerMutex.try_lock()) {
+ warn(Warning, Context);
+ dumpDIE(DIE, Options.Verbose);
+ ErrorHandlerMutex.unlock();
+ }
}
void DwarfLinkerForBinary::reportError(Twine Error, Twine Context,
const DWARFDie *DIE) const {
- std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
- error(Error, Context);
- dumpDIE(DIE, Options.Verbose);
+ // FIXME: implement error logging which does not block other threads.
+ if (ErrorHandlerMutex.try_lock()) {
+ error(Error, Context);
+ dumpDIE(DIE, Options.Verbose);
+ ErrorHandlerMutex.unlock();
+ }
}
ErrorOr<const object::ObjectFile &>
@@ -163,7 +167,7 @@
static Error remarksErrorHandler(const DebugMapObject &DMO,
DwarfLinkerForBinary &Linker,
std::unique_ptr<FileError> FE) {
- bool IsArchive = DMO.getObjectFilename().endswith(")");
+ bool IsArchive = DMO.getObjectFilename().ends_with(")");
// Don't report errors for missing remark files from static
// archives.
if (!IsArchive)
@@ -184,6 +188,42 @@
return createFileError(FE->getFileName(), std::move(NewE));
}
+Error DwarfLinkerForBinary::emitRelocations(
+ const DebugMap &DM, std::vector<ObjectWithRelocMap> &ObjectsForLinking) {
+ // Return early if the "Resources" directory is not being written to.
+ if (!Options.ResourceDir)
+ return Error::success();
+
+ RelocationMap RM(DM.getTriple(), DM.getBinaryPath());
+ for (auto &Obj : ObjectsForLinking) {
+ if (!Obj.OutRelocs->isInitialized())
+ continue;
+ Obj.OutRelocs->addValidRelocs(RM);
+ }
+
+ SmallString<128> InputPath;
+ SmallString<128> Path;
+ // Create the "Relocations" directory in the "Resources" directory, and
+ // create an architecture-specific directory in the "Relocations" directory.
+ StringRef ArchName = Triple::getArchName(RM.getTriple().getArch(),
+ RM.getTriple().getSubArch());
+ sys::path::append(Path, *Options.ResourceDir, "Relocations", ArchName);
+ if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
+ sys::fs::perms::all_all))
+ return errorCodeToError(EC);
+
+ // Append the file name.
+ sys::path::append(Path, sys::path::filename(DM.getBinaryPath()));
+ Path.append(".yml");
+
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OF_Text);
+ if (EC)
+ return errorCodeToError(EC);
+
+ RM.print(OS);
+ return Error::success();
+}
static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
StringRef ArchName, const remarks::RemarkLinker &RL) {
@@ -223,19 +263,32 @@
return Error::success();
}
-template <typename OutDWARFFile, typename AddressesMap>
-ErrorOr<std::unique_ptr<OutDWARFFile>>
-DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
- const DebugMap &DebugMap,
- remarks::RemarkLinker &RL) {
+ErrorOr<std::unique_ptr<DWARFFile>> DwarfLinkerForBinary::loadObject(
+ const DebugMapObject &Obj, const DebugMap &DebugMap,
+ remarks::RemarkLinker &RL,
+ std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM) {
auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
- std::unique_ptr<OutDWARFFile> Res;
+ std::unique_ptr<DWARFFile> Res;
if (ErrorOrObj) {
- Res = std::make_unique<OutDWARFFile>(
- Obj.getObjectFilename(), DWARFContext::create(*ErrorOrObj),
- std::make_unique<AddressesMap>(*this, *ErrorOrObj, Obj),
- Obj.empty() ? Obj.getWarnings() : EmptyWarnings);
+ auto Context = DWARFContext::create(
+ *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, nullptr,
+ "",
+ [&](Error Err) {
+ handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
+ reportError(Info.message());
+ });
+ },
+ [&](Error Warning) {
+ handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
+ reportWarning(Info.message());
+ });
+ });
+ DLBRM->init(*Context);
+ Res = std::make_unique<DWARFFile>(
+ Obj.getObjectFilename(), std::move(Context),
+ std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj, DLBRM),
+ [&](StringRef FileName) { BinHolder.eraseObjectEntry(FileName); });
Error E = RL.link(*ErrorOrObj);
if (Error NewE = handleErrors(
@@ -256,7 +309,7 @@
// need to copy them to the .dSYM. Only copy them for binaries where the
// linker omitted the reflection metadata.
if (!Map.getBinaryPath().empty() &&
- Options.FileType == DWARFLinker::OutputFileType::Object) {
+ Options.FileType == DWARFLinkerBase::OutputFileType::Object) {
auto ObjectEntry = BinHolder.getObjectEntry(Map.getBinaryPath());
// If ObjectEntry or Object has an error, no binary exists, therefore no
@@ -480,9 +533,8 @@
return Error::success();
}
-template <typename OutStreamer>
void DwarfLinkerForBinary::copySwiftReflectionMetadata(
- const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
+ const llvm::dsymutil::DebugMapObject *Obj, classic::DwarfStreamer *Streamer,
std::vector<uint64_t> &SectionToOffsetInDwarf,
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
&RelocationsToApply) {
@@ -540,28 +592,10 @@
}
bool DwarfLinkerForBinary::link(const DebugMap &Map) {
- if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::LLVM) {
- dwarflinker_parallel::DWARFLinker::OutputFileType DWARFLinkerOutputType;
- switch (Options.FileType) {
- case DWARFLinker::OutputFileType::Object:
- DWARFLinkerOutputType =
- dwarflinker_parallel::DWARFLinker::OutputFileType::Object;
- break;
+ if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::Parallel)
+ return linkImpl<parallel::DWARFLinker>(Map, Options.FileType);
- case DWARFLinker::OutputFileType::Assembly:
- DWARFLinkerOutputType =
- dwarflinker_parallel::DWARFLinker::OutputFileType::Assembly;
- break;
- }
-
- return linkImpl<dwarflinker_parallel::DWARFLinker,
- dwarflinker_parallel::DWARFFile,
- AddressManager<dwarflinker_parallel::AddressesMap>>(
- Map, DWARFLinkerOutputType);
- }
-
- return linkImpl<DWARFLinker, DWARFFile, AddressManager<AddressesMap>>(
- Map, Options.FileType);
+ return linkImpl<classic::DWARFLinker>(Map, Options.FileType);
}
template <typename Linker>
@@ -592,11 +626,11 @@
llvm_unreachable("All cases handled above!");
}
-template <typename Linker, typename OutDwarfFile, typename AddressMap>
+template <typename Linker>
bool DwarfLinkerForBinary::linkImpl(
const DebugMap &Map, typename Linker::OutputFileType ObjectType) {
- std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking;
+ std::vector<ObjectWithRelocMap> ObjectsForLinking;
DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
@@ -614,14 +648,32 @@
},
Options.Translator ? TranslationLambda : nullptr);
+ std::unique_ptr<classic::DwarfStreamer> Streamer;
if (!Options.NoOutput) {
- if (Error Err = GeneralLinker->createEmitter(Map.getTriple(), ObjectType,
- OutFile)) {
- handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+ if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
+ classic::DwarfStreamer::createStreamer(
+ Map.getTriple(), ObjectType, OutFile, Options.Translator,
+ [&](const Twine &Warning, StringRef Context,
+ const DWARFDie *DIE) {
+ reportWarning(Warning, Context, DIE);
+ }))
+ Streamer = std::move(*StreamerOrErr);
+ else {
+ handleAllErrors(StreamerOrErr.takeError(), [&](const ErrorInfoBase &EI) {
reportError(EI.message(), "dwarf streamer init");
});
return false;
}
+
+ if constexpr (std::is_same<Linker, parallel::DWARFLinker>::value) {
+ GeneralLinker->setOutputDWARFHandler(
+ Map.getTriple(),
+ [&](std::shared_ptr<parallel::SectionDescriptorBase> Section) {
+ Streamer->emitSectionContents(Section->getContents(),
+ Section->getKind());
+ });
+ } else
+ GeneralLinker->setOutputDWARFEmitter(Streamer.get());
}
remarks::RemarkLinker RL;
@@ -638,24 +690,29 @@
GeneralLinker->setNumThreads(Options.Threads);
GeneralLinker->setPrependPath(Options.PrependPath);
GeneralLinker->setKeepFunctionForStatic(Options.KeepFunctionForStatic);
- GeneralLinker->setInputVerificationHandler([&](const OutDwarfFile &File) {
- reportWarning("input verification failed", File.FileName);
- HasVerificationErrors = true;
- });
+ GeneralLinker->setInputVerificationHandler(
+ [&](const DWARFFile &File, llvm::StringRef Output) {
+ std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
+ if (Options.Verbose)
+ errs() << Output;
+ warn("input verification failed", File.FileName);
+ HasVerificationErrors = true;
+ });
auto Loader = [&](StringRef ContainerName,
- StringRef Path) -> ErrorOr<OutDwarfFile &> {
+ StringRef Path) -> ErrorOr<DWARFFile &> {
auto &Obj = DebugMap.addDebugMapObject(
Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
- if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
- loadObject<OutDwarfFile, AddressMap>(Obj, DebugMap, RL)) {
- ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
- return *ObjectsForLinking.back();
+ auto DLBRelocMap = std::make_shared<DwarfLinkerForBinaryRelocationMap>();
+ if (ErrorOr<std::unique_ptr<DWARFFile>> ErrorOrObj =
+ loadObject(Obj, DebugMap, RL, DLBRelocMap)) {
+ ObjectsForLinking.emplace_back(std::move(*ErrorOrObj), DLBRelocMap);
+ return *ObjectsForLinking.back().Object;
} else {
// Try and emit more helpful warnings by applying some heuristics.
StringRef ObjFile = ContainerName;
bool IsClangModule = sys::path::extension(Path).equals(".pcm");
- bool IsArchive = ObjFile.endswith(")");
+ bool IsArchive = ObjFile.ends_with(")");
if (IsClangModule) {
StringRef ModuleCacheDir = sys::path::parent_path(Path);
@@ -709,7 +766,7 @@
auto SectionToOffsetInDwarf =
calculateStartOfStrippableReflectionSections(Map);
for (const auto &Obj : Map.objects())
- copySwiftReflectionMetadata(Obj.get(), GeneralLinker->getEmitter(),
+ copySwiftReflectionMetadata(Obj.get(), Streamer.get(),
SectionToOffsetInDwarf, RelocationsToApply);
}
@@ -756,21 +813,23 @@
// Copy the module into the .swift_ast section.
if (!Options.NoOutput)
- GeneralLinker->getEmitter()->emitSwiftAST((*ErrorOrMem)->getBuffer());
+ Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
continue;
}
- if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
- loadObject<OutDwarfFile, AddressMap>(*Obj, Map, RL)) {
- ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
- GeneralLinker->addObjectFile(*ObjectsForLinking.back(), Loader,
+ auto DLBRelocMap = std::make_shared<DwarfLinkerForBinaryRelocationMap>();
+ if (ErrorOr<std::unique_ptr<DWARFFile>> ErrorOrObj =
+ loadObject(*Obj, Map, RL, DLBRelocMap)) {
+ ObjectsForLinking.emplace_back(std::move(*ErrorOrObj), DLBRelocMap);
+ GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object, Loader,
OnCUDieLoaded);
} else {
- ObjectsForLinking.push_back(std::make_unique<OutDwarfFile>(
- Obj->getObjectFilename(), nullptr, nullptr,
- Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
- GeneralLinker->addObjectFile(*ObjectsForLinking.back());
+ ObjectsForLinking.push_back(
+ {std::make_unique<DWARFFile>(Obj->getObjectFilename(), nullptr,
+ nullptr),
+ DLBRelocMap});
+ GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object);
}
}
@@ -795,6 +854,9 @@
if (Options.NoOutput)
return true;
+ if (Error E = emitRelocations(Map, ObjectsForLinking))
+ return error(toString(std::move(E)));
+
if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
if (auto E = copySwiftInterfaces(ArchName))
@@ -805,22 +867,18 @@
ObjectType == Linker::OutputFileType::Object)
return MachOUtils::generateDsymCompanion(
Options.VFS, Map, Options.Translator,
- *GeneralLinker->getEmitter()->getAsmPrinter().OutStreamer, OutFile,
- RelocationsToApply);
+ *Streamer->getAsmPrinter().OutStreamer, OutFile, RelocationsToApply);
- GeneralLinker->getEmitter()->finish();
+ Streamer->finish();
return true;
}
/// Iterate over the relocations of the given \p Section and
/// store the ones that correspond to debug map entries into the
/// ValidRelocs array.
-template <typename AddressesMapBase>
-void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
- findValidRelocsMachO(const object::SectionRef &Section,
- const object::MachOObjectFile &Obj,
- const DebugMapObject &DMO,
- std::vector<ValidReloc> &ValidRelocs) {
+void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
+ const object::SectionRef &Section, const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
Expected<StringRef> ContentsOrErr = Section.getContents();
if (!ContentsOrErr) {
consumeError(ContentsOrErr.takeError());
@@ -883,20 +941,21 @@
continue;
}
if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
- ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
+ ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping->getKey(),
+ Mapping->getValue());
} else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
// Do not store the addend. The addend was the address of the symbol in
// the object file, the address in the binary that is stored in the debug
// map doesn't need to be offset.
- ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
+ ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset,
+ Mapping->getKey(), Mapping->getValue());
}
}
}
/// Dispatch the valid relocation finding logic to the
/// appropriate handler depending on the object file format.
-template <typename AddressesMapBase>
-bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::findValidRelocs(
+bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
const object::SectionRef &Section, const object::ObjectFile &Obj,
const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
// Dispatch to the right handler depending on the file type.
@@ -921,10 +980,8 @@
/// entries in the debug map. These relocations will drive the Dwarf link by
/// indicating which DIEs refer to symbols present in the linked binary.
/// \returns whether there are any valid relocations in the debug info.
-template <typename AddressesMapBase>
-bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
- findValidRelocsInDebugSections(const object::ObjectFile &Obj,
- const DebugMapObject &DMO) {
+bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
+ const object::ObjectFile &Obj, const DebugMapObject &DMO) {
// Find the debug_info section.
bool FoundValidRelocs = false;
for (const object::SectionRef &Section : Obj.sections()) {
@@ -945,21 +1002,16 @@
return FoundValidRelocs;
}
-template <typename AddressesMapBase>
-std::vector<
- typename DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
-DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocations(
+std::vector<ValidReloc> DwarfLinkerForBinary::AddressManager::getRelocations(
const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
- std::vector<
- DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
- Res;
+ std::vector<ValidReloc> Res;
auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
- return Reloc.Offset < StartPos;
+ return (uint64_t)Reloc.Offset < StartPos;
});
while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos &&
- CurReloc->Offset < EndPos) {
+ (uint64_t)CurReloc->Offset < EndPos) {
Res.push_back(*CurReloc);
CurReloc++;
}
@@ -967,40 +1019,35 @@
return Res;
}
-template <typename AddressesMapBase>
-void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::printReloc(
- const ValidReloc &Reloc) {
- const auto &Mapping = Reloc.Mapping->getValue();
+void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {
+ const auto &Mapping = Reloc.SymbolMapping;
const uint64_t ObjectAddress = Mapping.ObjectAddress
? uint64_t(*Mapping.ObjectAddress)
: std::numeric_limits<uint64_t>::max();
- outs() << "Found valid debug map entry: " << Reloc.Mapping->getKey() << "\t"
+ outs() << "Found valid debug map entry: " << Reloc.SymbolName << "\t"
<< format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,
uint64_t(Mapping.BinaryAddress));
}
-template <typename AddressesMapBase>
-int64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocValue(
- const ValidReloc &Reloc) {
+int64_t
+DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) {
int64_t AddrAdjust = relocate(Reloc);
- if (Reloc.Mapping->getValue().ObjectAddress)
- AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
+ if (Reloc.SymbolMapping.ObjectAddress)
+ AddrAdjust -= uint64_t(*Reloc.SymbolMapping.ObjectAddress);
return AddrAdjust;
}
-template <typename AddressesMapBase>
std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager<AddressesMapBase>::hasValidRelocationAt(
+DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
- uint64_t EndOffset) {
+ uint64_t EndOffset, bool Verbose) {
std::vector<ValidReloc> Relocs =
getRelocations(AllRelocs, StartOffset, EndOffset);
-
if (Relocs.size() == 0)
return std::nullopt;
- if (Linker.Options.Verbose)
+ if (Verbose)
printReloc(Relocs[0]);
return getRelocValue(Relocs[0]);
@@ -1027,34 +1074,37 @@
return std::make_pair(Offset, End);
}
-template <typename AddressesMapBase>
-std::optional<int64_t> DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
- getExprOpAddressRelocAdjustment(DWARFUnit &U,
- const DWARFExpression::Operation &Op,
- uint64_t StartOffset, uint64_t EndOffset) {
+std::optional<int64_t>
+DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
+ DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
+ uint64_t EndOffset, bool Verbose) {
switch (Op.getCode()) {
default: {
assert(false && "Specified operation does not have address operand");
} break;
+ case dwarf::DW_OP_const2u:
case dwarf::DW_OP_const4u:
case dwarf::DW_OP_const8u:
+ case dwarf::DW_OP_const2s:
case dwarf::DW_OP_const4s:
case dwarf::DW_OP_const8s:
case dwarf::DW_OP_addr: {
- return hasValidRelocationAt(ValidDebugInfoRelocs, StartOffset, EndOffset);
+ return hasValidRelocationAt(ValidDebugInfoRelocs, StartOffset, EndOffset,
+ Verbose);
} break;
case dwarf::DW_OP_constx:
case dwarf::DW_OP_addrx: {
- return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset);
+ return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset,
+ Verbose);
} break;
}
return std::nullopt;
}
-template <typename AddressesMapBase>
-std::optional<int64_t> DwarfLinkerForBinary::AddressManager<
- AddressesMapBase>::getSubprogramRelocAdjustment(const DWARFDie &DIE) {
+std::optional<int64_t>
+DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
+ const DWARFDie &DIE, bool Verbose) {
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
std::optional<uint32_t> LowPcIdx =
@@ -1071,7 +1121,7 @@
std::tie(LowPcOffset, LowPcEndOffset) =
getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
return hasValidRelocationAt(ValidDebugInfoRelocs, LowPcOffset,
- LowPcEndOffset);
+ LowPcEndOffset, Verbose);
}
case dwarf::DW_FORM_addrx:
case dwarf::DW_FORM_addrx1:
@@ -1082,9 +1132,9 @@
if (std::optional<uint64_t> AddressOffset =
DIE.getDwarfUnit()->getIndexedAddressOffset(
AddrValue->getRawUValue()))
- return hasValidRelocationAt(ValidDebugAddrRelocs, *AddressOffset,
- *AddressOffset +
- DIE.getDwarfUnit()->getAddressByteSize());
+ return hasValidRelocationAt(
+ ValidDebugAddrRelocs, *AddressOffset,
+ *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(), Verbose);
Linker.reportWarning("no base offset for address table", SrcFileName);
return std::nullopt;
@@ -1094,12 +1144,32 @@
}
}
-template <typename AddressesMapBase>
-uint64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::relocate(
- const ValidReloc &Reloc) const {
- return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
+std::optional<StringRef>
+DwarfLinkerForBinary::AddressManager::getLibraryInstallName() {
+ return LibInstallName;
}
+uint64_t
+DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
+ return Reloc.SymbolMapping.BinaryAddress + Reloc.Addend;
+}
+
+void DwarfLinkerForBinary::AddressManager::updateAndSaveValidRelocs(
+ bool IsDWARF5, uint64_t OriginalUnitOffset, int64_t LinkedOffset,
+ uint64_t StartOffset, uint64_t EndOffset) {
+ std::vector<ValidReloc> InRelocs =
+ getRelocations(ValidDebugInfoRelocs, StartOffset, EndOffset);
+ if (IsDWARF5)
+ InRelocs = getRelocations(ValidDebugAddrRelocs, StartOffset, EndOffset);
+ DwarfLinkerRelocMap->updateAndSaveValidRelocs(
+ IsDWARF5, InRelocs, OriginalUnitOffset, LinkedOffset);
+}
+
+void DwarfLinkerForBinary::AddressManager::updateRelocationsWithUnitOffset(
+ uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {
+ DwarfLinkerRelocMap->updateRelocationsWithUnitOffset(OriginalUnitOffset,
+ OutputUnitOffset);
+}
/// Apply the valid relocations found by findValidRelocs() to
/// the buffer \p Data, taking into account that Data is at \p BaseOffset
/// in the debug_info section.
@@ -1108,9 +1178,9 @@
/// monotonic \p BaseOffset values.
///
/// \returns whether any reloc has been applied.
-template <typename AddressesMapBase>
-bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::applyValidRelocs(
+bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
+
std::vector<ValidReloc> Relocs = getRelocations(
ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
@@ -1126,9 +1196,47 @@
assert(CurReloc.Size <= sizeof(Buf));
memcpy(&Data[CurReloc.Offset - BaseOffset], Buf, CurReloc.Size);
}
-
return Relocs.size() > 0;
}
+void DwarfLinkerForBinaryRelocationMap::init(DWARFContext &Context) {
+ for (const std::unique_ptr<DWARFUnit> &CU : Context.compile_units())
+ StoredValidDebugInfoRelocsMap.insert(
+ std::make_pair(CU->getOffset(), std::vector<ValidReloc>()));
+ // FIXME: Support relocations debug_addr (DWARF5).
+}
+
+void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap &RM) {
+ for (const auto &DebugInfoRelocs : StoredValidDebugInfoRelocsMap) {
+ for (const auto &InfoReloc : DebugInfoRelocs.second)
+ RM.addRelocationMapEntry(InfoReloc);
+ }
+ // FIXME: Support relocations debug_addr (DWARF5).
+}
+
+void DwarfLinkerForBinaryRelocationMap::updateRelocationsWithUnitOffset(
+ uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {
+ std::vector<ValidReloc> &StoredValidDebugInfoRelocs =
+ StoredValidDebugInfoRelocsMap[OriginalUnitOffset];
+ for (ValidReloc &R : StoredValidDebugInfoRelocs) {
+ R.Offset = (uint64_t)R.Offset + OutputUnitOffset;
+ }
+ // FIXME: Support relocations debug_addr (DWARF5).
+}
+
+void DwarfLinkerForBinaryRelocationMap::updateAndSaveValidRelocs(
+ bool IsDWARF5, std::vector<ValidReloc> &InRelocs, uint64_t UnitOffset,
+ int64_t LinkedOffset) {
+ std::vector<ValidReloc> &OutRelocs =
+ StoredValidDebugInfoRelocsMap[UnitOffset];
+ if (IsDWARF5)
+ OutRelocs = StoredValidDebugAddrRelocsMap[UnitOffset];
+
+ for (ValidReloc &R : InRelocs) {
+ OutRelocs.emplace_back(R.Offset + LinkedOffset, R.Size, R.Addend,
+ R.SymbolName, R.SymbolMapping);
+ }
+}
+
} // namespace dsymutil
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.h
index 230f569..53f9e18 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.h
+++ b/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.h
@@ -13,18 +13,55 @@
#include "DebugMap.h"
#include "LinkUtils.h"
#include "MachOUtils.h"
-#include "llvm/DWARFLinker/DWARFLinker.h"
-#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
-#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
-#include "llvm/DWARFLinker/DWARFStreamer.h"
+#include "RelocationMap.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Remarks/RemarkFormat.h"
#include "llvm/Remarks/RemarkLinker.h"
#include <mutex>
+#include <optional>
namespace llvm {
+using namespace dwarf_linker;
+
namespace dsymutil {
+/// DwarfLinkerForBinaryRelocationMap contains the logic to handle the
+/// relocations and to store them inside an associated RelocationMap.
+class DwarfLinkerForBinaryRelocationMap {
+public:
+ void init(DWARFContext &Context);
+
+ bool isInitialized() {
+ return StoredValidDebugInfoRelocsMap.getMemorySize() != 0;
+ }
+
+ void addValidRelocs(RelocationMap &RM);
+
+ void updateAndSaveValidRelocs(bool IsDWARF5,
+ std::vector<ValidReloc> &InRelocs,
+ uint64_t UnitOffset, int64_t LinkedOffset);
+
+ void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
+ uint64_t OutputUnitOffset);
+
+ /// Map compilation unit offset to the valid relocations to store
+ /// @{
+ DenseMap<uint64_t, std::vector<ValidReloc>> StoredValidDebugInfoRelocsMap;
+ DenseMap<uint64_t, std::vector<ValidReloc>> StoredValidDebugAddrRelocsMap;
+ /// @}
+
+ DwarfLinkerForBinaryRelocationMap() = default;
+};
+
+struct ObjectWithRelocMap {
+ ObjectWithRelocMap(
+ std::unique_ptr<DWARFFile> Object,
+ std::shared_ptr<DwarfLinkerForBinaryRelocationMap> OutRelocs)
+ : Object(std::move(Object)), OutRelocs(OutRelocs) {}
+ std::unique_ptr<DWARFFile> Object;
+ std::shared_ptr<DwarfLinkerForBinaryRelocationMap> OutRelocs;
+};
+
/// The core of the Dsymutil Dwarf linking logic.
///
/// The link of the dwarf information from the object files will be
@@ -65,28 +102,12 @@
private:
/// Keeps track of relocations.
- template <typename AddressesMapBase>
- class AddressManager : public AddressesMapBase {
- struct ValidReloc {
- uint64_t Offset;
- uint32_t Size;
- uint64_t Addend;
- const DebugMapObject::DebugMapEntry *Mapping;
-
- ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend,
- const DebugMapObject::DebugMapEntry *Mapping)
- : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
-
- bool operator<(const ValidReloc &RHS) const {
- return Offset < RHS.Offset;
- }
- bool operator<(uint64_t RHS) const { return Offset < RHS; }
- };
+ class AddressManager : public dwarf_linker::AddressesMap {
const DwarfLinkerForBinary &Linker;
/// The valid relocations for the current DebugMapObject.
- /// This vector is sorted by relocation offset.
+ /// These vectors are sorted by relocation offset.
/// {
std::vector<ValidReloc> ValidDebugInfoRelocs;
std::vector<ValidReloc> ValidDebugAddrRelocs;
@@ -94,6 +115,12 @@
StringRef SrcFileName;
+ uint8_t DebugMapObjectType;
+
+ std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DwarfLinkerRelocMap;
+
+ std::optional<std::string> LibInstallName;
+
/// Returns list of valid relocations from \p Relocs,
/// between \p StartOffset and \p NextOffset.
///
@@ -115,9 +142,29 @@
public:
AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
- const DebugMapObject &DMO)
- : Linker(Linker), SrcFileName(DMO.getObjectFilename()) {
- findValidRelocsInDebugSections(Obj, DMO);
+ const DebugMapObject &DMO,
+ std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM)
+ : Linker(Linker), SrcFileName(DMO.getObjectFilename()),
+ DebugMapObjectType(MachO::N_OSO), DwarfLinkerRelocMap(DLBRM) {
+ if (DMO.getRelocationMap().has_value()) {
+ DebugMapObjectType = MachO::N_LIB;
+ LibInstallName.emplace(DMO.getInstallName().value());
+ const RelocationMap &RM = DMO.getRelocationMap().value();
+ for (const auto &Reloc : RM.relocations()) {
+ const auto *DebugMapEntry = DMO.lookupSymbol(Reloc.SymbolName);
+ if (!DebugMapEntry)
+ continue;
+ std::optional<uint64_t> ObjAddress;
+ ObjAddress.emplace(DebugMapEntry->getValue().ObjectAddress.value());
+ ValidDebugInfoRelocs.emplace_back(
+ Reloc.Offset, Reloc.Size, Reloc.Addend, Reloc.SymbolName,
+ SymbolMapping(ObjAddress, DebugMapEntry->getValue().BinaryAddress,
+ DebugMapEntry->getValue().Size));
+ // FIXME: Support relocations debug_addr.
+ }
+ } else {
+ findValidRelocsInDebugSections(Obj, DMO);
+ }
}
~AddressManager() override { clear(); }
@@ -145,22 +192,35 @@
/// Checks that there is a relocation in the \p Relocs array against a
/// debug map entry between \p StartOffset and \p NextOffset.
+ /// Print debug output if \p Verbose is set.
///
/// \returns relocation value if relocation exist, otherwise std::nullopt.
std::optional<int64_t>
hasValidRelocationAt(const std::vector<ValidReloc> &Relocs,
- uint64_t StartOffset, uint64_t EndOffset);
+ uint64_t StartOffset, uint64_t EndOffset,
+ bool Verbose);
std::optional<int64_t> getExprOpAddressRelocAdjustment(
DWARFUnit &U, const DWARFExpression::Operation &Op,
- uint64_t StartOffset, uint64_t EndOffset) override;
+ uint64_t StartOffset, uint64_t EndOffset, bool Verbose) override;
- std::optional<int64_t>
- getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
+ std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,
+ bool Verbose) override;
+
+ std::optional<StringRef> getLibraryInstallName() override;
bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
bool IsLittleEndian) override;
+ bool needToSaveValidRelocs() override { return true; }
+
+ void updateAndSaveValidRelocs(bool IsDWARF5, uint64_t OriginalUnitOffset,
+ int64_t LinkedOffset, uint64_t StartOffset,
+ uint64_t EndOffset) override;
+
+ void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
+ uint64_t OutputUnitOffset) override;
+
void clear() override {
ValidDebugInfoRelocs.clear();
ValidDebugAddrRelocs.clear();
@@ -180,11 +240,10 @@
/// Attempt to load a debug object from disk.
ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
const Triple &triple);
-
- template <typename OutDWARFFile, typename AddressesMap>
- ErrorOr<std::unique_ptr<OutDWARFFile>> loadObject(const DebugMapObject &Obj,
- const DebugMap &DebugMap,
- remarks::RemarkLinker &RL);
+ ErrorOr<std::unique_ptr<dwarf_linker::DWARFFile>>
+ loadObject(const DebugMapObject &Obj, const DebugMap &DebugMap,
+ remarks::RemarkLinker &RL,
+ std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM);
void collectRelocationsToApplyToSwiftReflectionSections(
const object::SectionRef &Section, StringRef &Contents,
@@ -196,17 +255,20 @@
Error copySwiftInterfaces(StringRef Architecture) const;
- template <typename OutStreamer>
void copySwiftReflectionMetadata(
- const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
+ const llvm::dsymutil::DebugMapObject *Obj,
+ classic::DwarfStreamer *Streamer,
std::vector<uint64_t> &SectionToOffsetInDwarf,
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
&RelocationsToApply);
- template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
+ template <typename Linker>
bool linkImpl(const DebugMap &Map,
typename Linker::OutputFileType ObjectType);
+ Error emitRelocations(const DebugMap &DM,
+ std::vector<ObjectWithRelocMap> &ObjectsForLinking);
+
raw_fd_ostream &OutFile;
BinaryHolder &BinHolder;
LinkOptions Options;
diff --git a/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h b/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h
index 88c17d5..fd9d985 100644
--- a/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h
+++ b/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h
@@ -16,8 +16,8 @@
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/WithColor.h"
-#include "llvm/DWARFLinker/DWARFLinker.h"
-#include "llvm/DWARFLinker/DWARFStreamer.h"
+#include "llvm/DWARFLinker/Classic/DWARFLinker.h"
+#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
#include <string>
namespace llvm {
@@ -32,8 +32,8 @@
};
enum class DsymutilDWARFLinkerType : uint8_t {
- Apple, /// Apple`s implementation of DWARFLinker.
- LLVM /// LLVM implementation of DWARFLinker.
+ Classic, /// Classic implementation of DWARFLinker.
+ Parallel /// Implementation of DWARFLinker heavily using parallel execution.
};
struct LinkOptions {
@@ -63,7 +63,7 @@
bool KeepFunctionForStatic = false;
/// Type of DWARFLinker to use.
- DsymutilDWARFLinkerType DWARFLinkerType = DsymutilDWARFLinkerType::Apple;
+ DsymutilDWARFLinkerType DWARFLinkerType = DsymutilDWARFLinkerType::Classic;
/// Use a 64-bit header when emitting universal binaries.
bool Fat64 = false;
@@ -72,7 +72,8 @@
unsigned Threads = 1;
// Output file type.
- DWARFLinker::OutputFileType FileType = DWARFLinker::OutputFileType::Object;
+ dwarf_linker::DWARFLinkerBase::OutputFileType FileType =
+ dwarf_linker::DWARFLinkerBase::OutputFileType::Object;
/// The accelerator table kind
DsymutilAccelTableKind TheAccelTableKind;
@@ -93,6 +94,12 @@
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
vfs::getRealFileSystem();
+ /// -build-variant-suffix.
+ std::string BuildVariantSuffix;
+
+ /// Paths where to search for the .dSYM files of merged libraries.
+ std::vector<std::string> DSYMSearchPaths;
+
/// Fields used for linking and placing remarks into the .dSYM bundle.
/// @{
diff --git a/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp b/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp
index d3bda33..6a9f256 100644
--- a/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp
@@ -9,6 +9,7 @@
#include "BinaryHolder.h"
#include "DebugMap.h"
#include "MachOUtils.h"
+#include "RelocationMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Object/MachO.h"
@@ -28,11 +29,13 @@
public:
MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
StringRef BinaryPath, ArrayRef<std::string> Archs,
- StringRef PathPrefix = "",
- bool PaperTrailWarnings = false, bool Verbose = false)
+ ArrayRef<std::string> DSYMSearchPaths,
+ StringRef PathPrefix = "", StringRef VariantSuffix = "",
+ bool Verbose = false)
: BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()),
+ DSYMSearchPaths(DSYMSearchPaths.begin(), DSYMSearchPaths.end()),
PathPrefix(std::string(PathPrefix)),
- PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose),
+ VariantSuffix(std::string(VariantSuffix)), BinHolder(VFS, Verbose),
CurrentDebugMapObject(nullptr), SkipDebugMapObject(false) {}
/// Parses and returns the DebugMaps of the input binary. The binary contains
@@ -49,8 +52,9 @@
private:
std::string BinaryPath;
SmallVector<StringRef, 1> Archs;
+ SmallVector<StringRef, 1> DSYMSearchPaths;
std::string PathPrefix;
- bool PaperTrailWarnings;
+ std::string VariantSuffix;
/// Owns the MemoryBuffer for the main binary.
BinaryHolder BinHolder;
@@ -90,6 +94,9 @@
void
switchToNewDebugMapObject(StringRef Filename,
sys::TimePoint<std::chrono::seconds> Timestamp);
+ void
+ switchToNewLibDebugMapObject(StringRef Filename,
+ sys::TimePoint<std::chrono::seconds> Timestamp);
void resetParserState();
uint64_t getMainBinarySymbolAddress(StringRef Name);
std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value);
@@ -137,13 +144,6 @@
<< MachOUtils::getArchName(
Result->getTriple().getArchName())
<< ") " << File << " " << Msg << "\n";
-
- if (PaperTrailWarnings) {
- if (!File.empty())
- Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>());
- if (Result->end() != Result->begin())
- (*--Result->end())->addWarning(Msg.str());
- }
}
};
@@ -210,9 +210,133 @@
CurrentDebugMapObject =
&Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO);
+
loadCurrentObjectFileSymbols(*Object);
}
+/// Create a new DebugMapObject of type MachO::N_LIB.
+/// This function resets the state of the parser that was
+/// referring to the last object file and sets everything
+/// up to add symbols to the new one.
+void MachODebugMapParser::switchToNewLibDebugMapObject(
+ StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
+
+ if (DSYMSearchPaths.empty()) {
+ Warning("no dSYM search path was specified");
+ return;
+ }
+
+ StringRef LeafName = sys::path::filename(Filename);
+ SmallString<128> VariantLeafName;
+ SmallString<128> ProductName(LeafName);
+
+ // For Framework.framework/Framework and -build-variant-suffix=_debug,
+ // look in the following order:
+ // 1) Framework.framework.dSYM/Contents/Resources/DWARF/Framework_debug
+ // 2) Framework.framework.dSYM/Contents/Resources/DWARF/Framework
+ //
+ // For libName.dylib and -build-variant-suffix=_debug,
+ // look in the following order:
+ // 1) libName.dylib.dSYM/Contents/Resources/DWARF/libName_debug.dylib
+ // 2) libName.dylib.dSYM/Contents/Resources/DWARF/libName.dylib
+
+ size_t libExt = LeafName.rfind(".dylib");
+ if (libExt != StringRef::npos) {
+ if (!VariantSuffix.empty()) {
+ VariantLeafName.append(LeafName.substr(0, libExt));
+ VariantLeafName.append(VariantSuffix);
+ VariantLeafName.append(".dylib");
+ }
+ } else {
+ // Expected to be a framework
+ ProductName.append(".framework");
+ if (!VariantSuffix.empty()) {
+ VariantLeafName.append(LeafName);
+ VariantLeafName.append(VariantSuffix);
+ }
+ }
+
+ for (auto DSYMSearchPath : DSYMSearchPaths) {
+ SmallString<256> Path(DSYMSearchPath);
+ SmallString<256> FallbackPath(Path);
+
+ SmallString<256> DSYMPath(ProductName);
+ DSYMPath.append(".dSYM");
+ sys::path::append(DSYMPath, "Contents", "Resources", "DWARF");
+
+ if (!VariantSuffix.empty()) {
+ sys::path::append(Path, DSYMPath, VariantLeafName);
+ sys::path::append(FallbackPath, DSYMPath, LeafName);
+ } else {
+ sys::path::append(Path, DSYMPath, LeafName);
+ }
+
+ auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp);
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ Warning("unable to open object file: " + toString(std::move(Err)),
+ Path.str());
+ if (!VariantSuffix.empty()) {
+ ObjectEntry = BinHolder.getObjectEntry(FallbackPath, Timestamp);
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ Warning("unable to open object file: " + toString(std::move(Err)),
+ FallbackPath.str());
+ continue;
+ }
+ Path.assign(FallbackPath);
+ } else {
+ continue;
+ }
+ }
+
+ auto Object =
+ ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple());
+ if (!Object) {
+ auto Err = Object.takeError();
+ Warning("unable to open object file: " + toString(std::move(Err)),
+ Path.str());
+ continue;
+ }
+
+ if (CurrentDebugMapObject &&
+ CurrentDebugMapObject->getType() == MachO::N_LIB &&
+ CurrentDebugMapObject->getObjectFilename().compare(Path.str()) == 0) {
+ return;
+ }
+
+ addCommonSymbols();
+ resetParserState();
+
+ CurrentDebugMapObject =
+ &Result->addDebugMapObject(Path, Timestamp, MachO::N_LIB);
+
+ CurrentDebugMapObject->setInstallName(Filename);
+
+ SmallString<256> RMPath(DSYMSearchPath);
+ sys::path::append(RMPath, ProductName);
+ RMPath.append(".dSYM");
+ StringRef ArchName = Triple::getArchName(Result->getTriple().getArch(),
+ Result->getTriple().getSubArch());
+ sys::path::append(RMPath, "Contents", "Resources", "Relocations", ArchName);
+ sys::path::append(RMPath, LeafName);
+ RMPath.append(".yml");
+ const auto &RelocMapPtrOrErr =
+ RelocationMap::parseYAMLRelocationMap(RMPath, PathPrefix);
+ if (auto EC = RelocMapPtrOrErr.getError()) {
+ Warning("cannot parse relocation map file: " + EC.message(),
+ RMPath.str());
+ return;
+ }
+ CurrentDebugMapObject->setRelocationMap(*RelocMapPtrOrErr->get());
+
+ loadCurrentObjectFileSymbols(*Object);
+
+ // Found and loaded new dSYM file
+ return;
+ }
+}
+
static std::string getArchName(const object::MachOObjectFile &Obj) {
Triple T = Obj.getArchTriple();
return std::string(T.getArchName());
@@ -285,23 +409,39 @@
const char *Name;
};
-const struct DarwinStabName DarwinStabNames[] = {
- {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"},
- {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"},
- {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"},
- {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"},
- {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"},
- {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"},
- {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"},
- {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"},
- {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"},
- {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"},
- {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"},
- {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"},
- {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"},
- {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"},
- {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"},
- {MachO::N_LENG, "N_LENG"}, {0, nullptr}};
+const struct DarwinStabName DarwinStabNames[] = {{MachO::N_GSYM, "N_GSYM"},
+ {MachO::N_FNAME, "N_FNAME"},
+ {MachO::N_FUN, "N_FUN"},
+ {MachO::N_STSYM, "N_STSYM"},
+ {MachO::N_LCSYM, "N_LCSYM"},
+ {MachO::N_BNSYM, "N_BNSYM"},
+ {MachO::N_PC, "N_PC"},
+ {MachO::N_AST, "N_AST"},
+ {MachO::N_OPT, "N_OPT"},
+ {MachO::N_RSYM, "N_RSYM"},
+ {MachO::N_SLINE, "N_SLINE"},
+ {MachO::N_ENSYM, "N_ENSYM"},
+ {MachO::N_SSYM, "N_SSYM"},
+ {MachO::N_SO, "N_SO"},
+ {MachO::N_OSO, "N_OSO"},
+ {MachO::N_LIB, "N_LIB"},
+ {MachO::N_LSYM, "N_LSYM"},
+ {MachO::N_BINCL, "N_BINCL"},
+ {MachO::N_SOL, "N_SOL"},
+ {MachO::N_PARAMS, "N_PARAM"},
+ {MachO::N_VERSION, "N_VERS"},
+ {MachO::N_OLEVEL, "N_OLEV"},
+ {MachO::N_PSYM, "N_PSYM"},
+ {MachO::N_EINCL, "N_EINCL"},
+ {MachO::N_ENTRY, "N_ENTRY"},
+ {MachO::N_LBRAC, "N_LBRAC"},
+ {MachO::N_EXCL, "N_EXCL"},
+ {MachO::N_RBRAC, "N_RBRAC"},
+ {MachO::N_BCOMM, "N_BCOMM"},
+ {MachO::N_ECOMM, "N_ECOMM"},
+ {MachO::N_ECOML, "N_ECOML"},
+ {MachO::N_LENG, "N_LENG"},
+ {0, nullptr}};
static const char *getDarwinStabString(uint8_t NType) {
for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
@@ -409,11 +549,11 @@
if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*"))
return true;
- if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm"))
+ if (Arch.starts_with("arm") && Arch != "arm64" && is_contained(Archs, "arm"))
return true;
SmallString<16> ArchName = Arch;
- if (Arch.startswith("thumb"))
+ if (Arch.starts_with("thumb"))
ArchName = ("arm" + Arch.substr(5)).str();
return is_contained(Archs, ArchName);
@@ -487,13 +627,25 @@
const char *Name = &MainBinaryStrings.data()[StringIndex];
+ // An N_LIB entry represents the start of a new library file description.
+ if (Type == MachO::N_LIB) {
+ switchToNewLibDebugMapObject(Name, sys::toTimePoint(Value));
+ return;
+ }
+
// An N_OSO entry represents the start of a new object file description.
+ // If an N_LIB entry was present, this is parsed only if the library
+ // dSYM file could not be found.
if (Type == MachO::N_OSO) {
- if (Duplicates.count(OSO(Name, Value))) {
- SkipDebugMapObject = true;
- return;
+ if (!CurrentDebugMapObject ||
+ CurrentDebugMapObject->getType() != MachO::N_LIB) {
+ if (Duplicates.count(OSO(Name, Value))) {
+ SkipDebugMapObject = true;
+ return;
+ }
+ switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
}
- return switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
+ return;
}
if (SkipDebugMapObject)
@@ -576,7 +728,8 @@
}
if (ObjectSymIt == CurrentObjectAddresses.end()) {
- Warning("could not find object file symbol for symbol " + Twine(Name));
+ Warning("could not find symbol '" + Twine(Name) + "' in object file '" +
+ CurrentDebugMapObject->getObjectFilename() + "'");
return;
}
@@ -704,20 +857,23 @@
llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
- bool InputIsYAML) {
+ ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
+ StringRef VariantSuffix, bool Verbose, bool InputIsYAML) {
if (InputIsYAML)
return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
- MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath,
- PaperTrailWarnings, Verbose);
+ MachODebugMapParser Parser(VFS, InputFile, Archs, DSYMSearchPaths,
+ PrependPath, VariantSuffix, Verbose);
+
return Parser.parse();
}
bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath) {
- MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false);
+ ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
+ StringRef VariantSuffix) {
+ MachODebugMapParser Parser(VFS, InputFile, Archs, DSYMSearchPaths,
+ PrependPath, VariantSuffix, false);
return Parser.dumpStab();
}
} // namespace dsymutil
diff --git a/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp b/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp
index 9d440e8..3efc1af 100644
--- a/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp
@@ -10,6 +10,7 @@
#include "BinaryHolder.h"
#include "DebugMap.h"
#include "LinkUtils.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/NonRelocatableStringpool.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
@@ -29,28 +30,34 @@
namespace MachOUtils {
llvm::Error ArchAndFile::createTempFile() {
- llvm::SmallString<128> TmpModel;
- llvm::sys::path::system_temp_directory(true, TmpModel);
- llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
- Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel);
+ SmallString<256> SS;
+ std::error_code EC = sys::fs::createTemporaryFile("dsym", "dwarf", FD, SS);
- if (!T)
- return T.takeError();
+ if (EC)
+ return errorCodeToError(EC);
- File = std::make_unique<sys::fs::TempFile>(std::move(*T));
+ Path = SS.str();
+
return Error::success();
}
-llvm::StringRef ArchAndFile::path() const { return File->TmpName; }
+llvm::StringRef ArchAndFile::getPath() const {
+ assert(!Path.empty() && "path called before createTempFile");
+ return Path;
+}
+
+int ArchAndFile::getFD() const {
+ assert((FD != -1) && "path called before createTempFile");
+ return FD;
+}
ArchAndFile::~ArchAndFile() {
- if (File)
- if (auto E = File->discard())
- llvm::consumeError(std::move(E));
+ if (!Path.empty())
+ sys::fs::remove(Path);
}
std::string getArchName(StringRef Arch) {
- if (Arch.startswith("thumb"))
+ if (Arch.starts_with("thumb"))
return (llvm::Twine("arm") + Arch.drop_front(5)).str();
return std::string(Arch);
}
@@ -82,11 +89,17 @@
bool Fat64) {
// No need to merge one file into a universal fat binary.
if (ArchFiles.size() == 1) {
- if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
- WithColor::error() << "while keeping " << ArchFiles.front().path()
- << " as " << OutputFileName << ": "
- << toString(std::move(E)) << "\n";
- return false;
+ llvm::StringRef TmpPath = ArchFiles.front().getPath();
+ if (auto EC = sys::fs::rename(TmpPath, OutputFileName)) {
+ // If we can't rename, try to copy to work around cross-device link
+ // issues.
+ EC = sys::fs::copy_file(TmpPath, OutputFileName);
+ if (EC) {
+ WithColor::error() << "while keeping " << TmpPath << " as "
+ << OutputFileName << ": " << EC.message() << "\n";
+ return false;
+ }
+ sys::fs::remove(TmpPath);
}
return true;
}
@@ -96,7 +109,7 @@
Args.push_back("-create");
for (auto &Thin : ArchFiles)
- Args.push_back(Thin.path());
+ Args.push_back(Thin.getPath());
// Align segments to match dsymutil-classic alignment.
for (auto &Thin : ArchFiles) {
@@ -328,8 +341,9 @@
VMAddr = alignTo(VMAddr, Alignment);
FileOffset = alignTo(FileOffset, Alignment);
if (FileOffset > UINT32_MAX)
- return error("section " + Sec->getName() + "'s file offset exceeds 4GB."
- " Refusing to produce an invalid Mach-O file.");
+ return error("section " + Sec->getName() +
+ "'s file offset exceeds 4GB."
+ " Refusing to produce an invalid Mach-O file.");
}
Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0);
@@ -414,7 +428,7 @@
++NumLoadCommands;
LoadCommandSize += sizeof(UUIDCmd);
break;
- case MachO::LC_BUILD_VERSION: {
+ case MachO::LC_BUILD_VERSION: {
MachO::build_version_command Cmd;
memset(&Cmd, 0, sizeof(Cmd));
Cmd = InputBinary.getBuildVersionLoadCommand(LCI);
diff --git a/src/llvm-project/llvm/tools/dsymutil/MachOUtils.h b/src/llvm-project/llvm/tools/dsymutil/MachOUtils.h
index 9d35813..059d9fd 100644
--- a/src/llvm-project/llvm/tools/dsymutil/MachOUtils.h
+++ b/src/llvm-project/llvm/tools/dsymutil/MachOUtils.h
@@ -26,10 +26,12 @@
struct ArchAndFile {
std::string Arch;
- std::unique_ptr<llvm::sys::fs::TempFile> File;
+ std::string Path;
+ int FD = -1;
llvm::Error createTempFile();
- llvm::StringRef path() const;
+ llvm::StringRef getPath() const;
+ int getFD() const;
ArchAndFile(StringRef Arch) : Arch(std::string(Arch)) {}
ArchAndFile(ArchAndFile &&A) = default;
diff --git a/src/llvm-project/llvm/tools/dsymutil/Options.td b/src/llvm-project/llvm/tools/dsymutil/Options.td
index 9b0b31b..a4e4c6c 100644
--- a/src/llvm-project/llvm/tools/dsymutil/Options.td
+++ b/src/llvm-project/llvm/tools/dsymutil/Options.td
@@ -69,10 +69,6 @@
HelpText<"Treat the input file is a YAML debug map rather than a binary.">,
Group<grp_general>;
-def papertrail: F<"papertrail">,
- HelpText<"Embed warnings in the linked DWARF debug info.">,
- Group<grp_general>;
-
def assembly: Flag<["-", "--"], "S">,
HelpText<"Output textual assembly instead of a binary dSYM companion file.">,
Group<grp_general>;
@@ -202,6 +198,17 @@
def linker: Separate<["--", "-"], "linker">,
MetaVarName<"<DWARF linker type>">,
- HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">,
+ HelpText<"Specify the desired type of DWARF linker. Defaults to 'classic'">,
Group<grp_general>;
def: Joined<["--", "-"], "linker=">, Alias<linker>;
+
+def build_variant_suffix: Separate<["--", "-"], "build-variant-suffix">,
+ MetaVarName<"<suffix=buildvariant>">,
+ HelpText<"Specify the build variant suffix used to build the executabe file.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "build-variant-suffix=">, Alias<build_variant_suffix>;
+
+def dsym_search_path: Separate<["-", "--"], "D">,
+ MetaVarName<"<path>">,
+ HelpText<"Specify a directory that contain dSYM files to search for.">,
+ Group<grp_general>;
diff --git a/src/llvm-project/llvm/tools/dsymutil/RelocationMap.cpp b/src/llvm-project/llvm/tools/dsymutil/RelocationMap.cpp
new file mode 100644
index 0000000..5921e7c
--- /dev/null
+++ b/src/llvm-project/llvm/tools/dsymutil/RelocationMap.cpp
@@ -0,0 +1,92 @@
+//===- tools/dsymutil/RelocationMap.cpp - Relocation map representation---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RelocationMap.h"
+
+namespace llvm {
+
+namespace dsymutil {
+
+void RelocationMap::print(raw_ostream &OS) const {
+ yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
+ yout << const_cast<RelocationMap &>(*this);
+}
+
+#ifndef NDEBUG
+void RelocationMap::dump() const { print(errs()); }
+#endif
+
+void RelocationMap::addRelocationMapEntry(const ValidReloc &Relocation) {
+ Relocations.push_back(Relocation);
+}
+
+namespace {
+
+struct YAMLContext {
+ StringRef PrependPath;
+ Triple BinaryTriple;
+};
+
+} // end anonymous namespace
+
+ErrorOr<std::unique_ptr<RelocationMap>>
+RelocationMap::parseYAMLRelocationMap(StringRef InputFile,
+ StringRef PrependPath) {
+ auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
+ if (auto Err = ErrOrFile.getError())
+ return Err;
+
+ YAMLContext Ctxt;
+
+ Ctxt.PrependPath = PrependPath;
+
+ std::unique_ptr<RelocationMap> Result;
+ yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
+ yin >> Result;
+
+ if (auto EC = yin.error())
+ return EC;
+ return std::move(Result);
+}
+
+} // end namespace dsymutil
+
+namespace yaml {
+
+void MappingTraits<dsymutil::ValidReloc>::mapping(IO &io,
+ dsymutil::ValidReloc &VR) {
+ io.mapRequired("offset", VR.Offset);
+ io.mapRequired("size", VR.Size);
+ io.mapRequired("addend", VR.Addend);
+ io.mapRequired("symName", VR.SymbolName);
+ io.mapOptional("symObjAddr", VR.SymbolMapping.ObjectAddress);
+ io.mapRequired("symBinAddr", VR.SymbolMapping.BinaryAddress);
+ io.mapRequired("symSize", VR.SymbolMapping.Size);
+}
+
+void MappingTraits<dsymutil::RelocationMap>::mapping(
+ IO &io, dsymutil::RelocationMap &RM) {
+ io.mapRequired("triple", RM.BinaryTriple);
+ io.mapRequired("binary-path", RM.BinaryPath);
+ if (void *Ctxt = io.getContext())
+ reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = RM.BinaryTriple;
+ io.mapRequired("relocations", RM.Relocations);
+}
+
+void MappingTraits<std::unique_ptr<dsymutil::RelocationMap>>::mapping(
+ IO &io, std::unique_ptr<dsymutil::RelocationMap> &RM) {
+ if (!RM)
+ RM.reset(new RelocationMap());
+ io.mapRequired("triple", RM->BinaryTriple);
+ io.mapRequired("binary-path", RM->BinaryPath);
+ if (void *Ctxt = io.getContext())
+ reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = RM->BinaryTriple;
+ io.mapRequired("relocations", RM->Relocations);
+}
+} // end namespace yaml
+} // end namespace llvm
diff --git a/src/llvm-project/llvm/tools/dsymutil/RelocationMap.h b/src/llvm-project/llvm/tools/dsymutil/RelocationMap.h
new file mode 100644
index 0000000..3d851ac
--- /dev/null
+++ b/src/llvm-project/llvm/tools/dsymutil/RelocationMap.h
@@ -0,0 +1,160 @@
+//===- tools/dsymutil/RelocationMap.h -------------------------- *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// This file contains the class declaration of the RelocationMap
+/// entity. RelocationMap lists all the relocations of all the
+/// atoms used in the object files linked together to
+/// produce an executable.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H
+#define LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace dsymutil {
+
+struct SymbolMapping {
+ std::optional<yaml::Hex64> ObjectAddress;
+ yaml::Hex64 BinaryAddress;
+ yaml::Hex32 Size;
+
+ SymbolMapping(std::optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
+ uint32_t Size)
+ : BinaryAddress(BinaryAddress), Size(Size) {
+ if (ObjectAddr)
+ ObjectAddress = *ObjectAddr;
+ }
+
+ /// For YAML IO support
+ SymbolMapping() = default;
+};
+
+/// ValidReloc represents one relocation entry described by the RelocationMap.
+/// It contains a list of DWARF relocations to apply to a linked binary.
+class ValidReloc {
+public:
+ yaml::Hex64 Offset;
+ yaml::Hex32 Size;
+ yaml::Hex64 Addend;
+ std::string SymbolName;
+ struct SymbolMapping SymbolMapping;
+
+ struct SymbolMapping getSymbolMapping() const { return SymbolMapping; }
+
+ ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend,
+ StringRef SymbolName, struct SymbolMapping SymbolMapping)
+ : Offset(Offset), Size(Size), Addend(Addend), SymbolName(SymbolName),
+ SymbolMapping(SymbolMapping) {}
+
+ bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
+
+ /// For YAMLIO support.
+ ValidReloc() = default;
+};
+
+/// The RelocationMap object stores the list of relocation entries for a binary
+class RelocationMap {
+ Triple BinaryTriple;
+ std::string BinaryPath;
+ using RelocContainer = std::vector<ValidReloc>;
+
+ RelocContainer Relocations;
+
+ /// For YAML IO support.
+ ///@{
+ friend yaml::MappingTraits<std::unique_ptr<RelocationMap>>;
+ friend yaml::MappingTraits<RelocationMap>;
+
+ RelocationMap() = default;
+ ///@}
+
+public:
+ RelocationMap(const Triple &BinaryTriple, StringRef BinaryPath)
+ : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)) {}
+
+ using const_iterator = RelocContainer::const_iterator;
+
+ iterator_range<const_iterator> relocations() const {
+ return make_range(begin(), end());
+ }
+
+ const_iterator begin() const { return Relocations.begin(); }
+
+ const_iterator end() const { return Relocations.end(); }
+
+ size_t getNumberOfEntries() const { return Relocations.size(); }
+
+ /// This function adds a ValidReloc to the list owned by this
+ /// relocation map.
+ void addRelocationMapEntry(const ValidReloc &Relocation);
+
+ const Triple &getTriple() const { return BinaryTriple; }
+
+ StringRef getBinaryPath() const { return BinaryPath; }
+
+ void print(raw_ostream &OS) const;
+
+#ifndef NDEBUG
+ void dump() const;
+#endif
+
+ /// Read a relocation map from \a InputFile.
+ static ErrorOr<std::unique_ptr<RelocationMap>>
+ parseYAMLRelocationMap(StringRef InputFile, StringRef PrependPath);
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(dsymutil::ValidReloc)
+
+namespace llvm {
+namespace yaml {
+
+using namespace llvm::dsymutil;
+
+template <> struct MappingTraits<dsymutil::ValidReloc> {
+ static void mapping(IO &io, dsymutil::ValidReloc &VR);
+ static const bool flow = true;
+};
+
+template <> struct MappingTraits<dsymutil::RelocationMap> {
+ struct YamlRM;
+ static void mapping(IO &io, dsymutil::RelocationMap &RM);
+};
+
+template <> struct MappingTraits<std::unique_ptr<dsymutil::RelocationMap>> {
+ struct YamlRM;
+ static void mapping(IO &io, std::unique_ptr<dsymutil::RelocationMap> &RM);
+};
+
+template <> struct ScalarTraits<Triple> {
+ static void output(const Triple &val, void *, raw_ostream &out);
+ static StringRef input(StringRef scalar, void *, Triple &value);
+ static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H
diff --git a/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp b/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp
index 2522e2c..a6cc104 100644
--- a/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp
@@ -8,6 +8,7 @@
#include "Reproducer.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
using namespace llvm;
using namespace llvm::dsymutil;
@@ -16,7 +17,12 @@
SmallString<128> Root;
if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) {
Root.assign(Path);
- EC = sys::fs::create_directory(Root);
+ EC = sys::fs::create_directories(Root);
+ } else if (const char *Path = getenv("LLVM_DIAGNOSTIC_DIR")) {
+ Root.assign(Path);
+ llvm::sys::path::append(
+ Root, "dsymutil-" + llvm::Twine(llvm::sys::Process::getProcessId()));
+ EC = sys::fs::create_directories(Root);
} else {
EC = sys::fs::createUniqueDirectory("dsymutil", Root);
}
diff --git a/src/llvm-project/llvm/tools/dsymutil/SymbolMap.cpp b/src/llvm-project/llvm/tools/dsymutil/SymbolMap.cpp
index 07a5479..c55362e 100644
--- a/src/llvm-project/llvm/tools/dsymutil/SymbolMap.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/SymbolMap.cpp
@@ -23,15 +23,11 @@
namespace dsymutil {
StringRef SymbolMapTranslator::operator()(StringRef Input) {
- if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#"))
+ if (!Input.starts_with("__hidden#") && !Input.starts_with("___hidden#"))
return Input;
- bool MightNeedUnderscore = false;
StringRef Line = Input.drop_front(sizeof("__hidden#") - 1);
- if (Line[0] == '#') {
- Line = Line.drop_front();
- MightNeedUnderscore = true;
- }
+ bool MightNeedUnderscore = Line.consume_front("#");
std::size_t LineNumber = std::numeric_limits<std::size_t>::max();
Line.split('_').first.getAsInteger(10, LineNumber);
@@ -131,7 +127,7 @@
bool MangleNames = false;
// Check version string first.
- if (!LHS.startswith("BCSymbolMap Version:")) {
+ if (!LHS.starts_with("BCSymbolMap Version:")) {
// Version string not present, warns but try to parse it.
WithColor::warning() << SymbolMapPath
<< " is missing version string: assuming 1.0.\n";
diff --git a/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp b/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp
index 5a8d219..b0e988c 100644
--- a/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp
@@ -37,7 +37,6 @@
#include "llvm/Support/FileCollector.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
@@ -55,13 +54,12 @@
using namespace llvm;
using namespace llvm::dsymutil;
using namespace object;
+using namespace llvm::dwarf_linker;
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Options.inc"
#undef OPTION
};
@@ -73,14 +71,9 @@
#include "Options.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Options.inc"
#undef OPTION
};
@@ -99,7 +92,7 @@
All = Input | Output,
Auto = Input | OutputOnValidInput,
#if !defined(NDEBUG) || defined(EXPENSIVE_CHECKS)
- Default = None // FIXME: Auto
+ Default = Auto
#else
Default = None
#endif
@@ -114,7 +107,6 @@
bool DumpStab = false;
bool Flat = false;
bool InputIsYAMLDebugMap = false;
- bool PaperTrailWarnings = false;
bool ForceKeepFunctionForStatic = false;
std::string SymbolMap;
std::string OutputFile;
@@ -205,11 +197,6 @@
"cannot use -o with multiple inputs in flat mode.",
errc::invalid_argument);
- if (Options.PaperTrailWarnings && Options.InputIsYAMLDebugMap)
- return make_error<StringError>(
- "paper trail warnings are not supported for YAML input.",
- errc::invalid_argument);
-
if (!Options.ReproducerPath.empty() &&
Options.ReproMode != ReproducerMode::Use)
return make_error<StringError>(
@@ -245,18 +232,18 @@
getDWARFLinkerType(opt::InputArgList &Args) {
if (opt::Arg *LinkerType = Args.getLastArg(OPT_linker)) {
StringRef S = LinkerType->getValue();
- if (S == "apple")
- return DsymutilDWARFLinkerType::Apple;
- if (S == "llvm")
- return DsymutilDWARFLinkerType::LLVM;
+ if (S == "classic")
+ return DsymutilDWARFLinkerType::Classic;
+ if (S == "parallel")
+ return DsymutilDWARFLinkerType::Parallel;
return make_error<StringError>("invalid DWARF linker type specified: '" +
S +
- "'. Supported values are 'apple', "
- "'llvm'.",
+ "'. Supported values are 'classic', "
+ "'parallel'.",
inconvertibleErrorCode());
}
- return DsymutilDWARFLinkerType::Apple;
+ return DsymutilDWARFLinkerType::Classic;
}
static Expected<ReproducerMode> getReproducerMode(opt::InputArgList &Args) {
@@ -311,7 +298,6 @@
Options.DumpStab = Args.hasArg(OPT_symtab);
Options.Flat = Args.hasArg(OPT_flat);
Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input);
- Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail);
if (Expected<DWARFVerify> Verify = getVerifyKind(Args)) {
Options.Verify = *Verify;
@@ -387,7 +373,7 @@
Options.Toolchain = Toolchain->getValue();
if (Args.hasArg(OPT_assembly))
- Options.LinkOpts.FileType = DWARFLinker::OutputFileType::Assembly;
+ Options.LinkOpts.FileType = DWARFLinkerBase::OutputFileType::Assembly;
if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
Options.LinkOpts.Threads = atoi(NumThreads->getValue());
@@ -397,9 +383,6 @@
if (Options.DumpDebugMap || Options.LinkOpts.Verbose)
Options.LinkOpts.Threads = 1;
- if (getenv("RC_DEBUG_OPTIONS"))
- Options.PaperTrailWarnings = true;
-
if (opt::Arg *RemarksPrependPath = Args.getLastArg(OPT_remarks_prepend_path))
Options.LinkOpts.RemarksPrependPath = RemarksPrependPath->getValue();
@@ -415,6 +398,12 @@
Options.LinkOpts.RemarksKeepAll =
!Args.hasArg(OPT_remarks_drop_without_debug);
+ if (opt::Arg *BuildVariantSuffix = Args.getLastArg(OPT_build_variant_suffix))
+ Options.LinkOpts.BuildVariantSuffix = BuildVariantSuffix->getValue();
+
+ for (auto *SearchPath : Args.filtered(OPT_dsym_search_path))
+ Options.LinkOpts.DSYMSearchPaths.push_back(SearchPath->getValue());
+
if (Error E = verifyOptions(Options))
return std::move(E);
return Options;
@@ -498,15 +487,17 @@
}
static bool verifyOutput(StringRef OutputFile, StringRef Arch,
- DsymutilOptions Options) {
+ DsymutilOptions Options, std::mutex &Mutex) {
if (OutputFile == "-") {
+ std::lock_guard<std::mutex> Guard(Mutex);
WithColor::warning() << "verification skipped for " << Arch
<< " because writing to stdout.\n";
return true;
}
if (Options.LinkOpts.NoOutput) {
+ std::lock_guard<std::mutex> Guard(Mutex);
WithColor::warning() << "verification skipped for " << Arch
<< " because --no-output was passed.\n";
return true;
@@ -514,6 +505,7 @@
Expected<OwningBinary<Binary>> BinOrErr = createBinary(OutputFile);
if (!BinOrErr) {
+ std::lock_guard<std::mutex> Guard(Mutex);
WithColor::error() << OutputFile << ": " << toString(BinOrErr.takeError());
return false;
}
@@ -521,17 +513,29 @@
Binary &Binary = *BinOrErr.get().getBinary();
if (auto *Obj = dyn_cast<MachOObjectFile>(&Binary)) {
std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
- if (DICtx->getMaxVersion() >= 5) {
- WithColor::warning() << "verification skipped for " << Arch
- << " because DWARFv5 is not fully supported yet.\n";
+ if (DICtx->getMaxVersion() > 5) {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ WithColor::warning()
+ << "verification skipped for " << Arch
+ << " because DWARF standard greater than v5 is not supported yet.\n";
return true;
}
- raw_ostream &os = Options.LinkOpts.Verbose ? errs() : nulls();
- os << "Verifying DWARF for architecture: " << Arch << "\n";
+
+ if (Options.LinkOpts.Verbose) {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ errs() << "Verifying DWARF for architecture: " << Arch << "\n";
+ }
+
+ std::string Buffer;
+ raw_string_ostream OS(Buffer);
+
DIDumpOptions DumpOpts;
- bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion());
- if (!success)
+ bool success = DICtx->verify(OS, DumpOpts.noImplicitRecursion());
+ if (!success) {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ errs() << OS.str();
WithColor::error() << "output verification failed for " << Arch << '\n';
+ }
return success;
}
@@ -597,14 +601,12 @@
}
sys::path::append(Path, "Contents", "Resources");
- std::string ResourceDir = std::string(Path.str());
+ std::string ResourceDir = std::string(Path);
sys::path::append(Path, "DWARF", sys::path::filename(DwarfFile));
- return OutputLocation(std::string(Path.str()), ResourceDir);
+ return OutputLocation(std::string(Path), ResourceDir);
}
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
-
+int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
// Parse arguments.
DsymutilOptTable T;
unsigned MAI;
@@ -672,15 +674,18 @@
// Dump the symbol table for each input file and requested arch
if (Options.DumpStab) {
if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs,
- Options.LinkOpts.PrependPath))
+ Options.LinkOpts.DSYMSearchPaths,
+ Options.LinkOpts.PrependPath,
+ Options.LinkOpts.BuildVariantSuffix))
return EXIT_FAILURE;
continue;
}
- auto DebugMapPtrsOrErr =
- parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs,
- Options.LinkOpts.PrependPath, Options.PaperTrailWarnings,
- Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
+ auto DebugMapPtrsOrErr = parseDebugMap(
+ Options.LinkOpts.VFS, InputFile, Options.Archs,
+ Options.LinkOpts.DSYMSearchPaths, Options.LinkOpts.PrependPath,
+ Options.LinkOpts.BuildVariantSuffix, Options.LinkOpts.Verbose,
+ Options.InputIsYAMLDebugMap);
if (auto EC = DebugMapPtrsOrErr.getError()) {
WithColor::error() << "cannot parse the debug map for '" << InputFile
@@ -737,16 +742,16 @@
!Options.DumpDebugMap && (Options.OutputFile != "-") &&
(DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update);
- // Set up a crash recovery context.
- CrashRecoveryContext::Enable();
- CrashRecoveryContext CRC;
- CRC.DumpStackAndCleanupOnFailure = true;
-
std::atomic_char AllOK(1);
SmallVector<MachOUtils::ArchAndFile, 4> TempFiles;
std::mutex ErrorHandlerMutex;
+ // Set up a crash recovery context.
+ CrashRecoveryContext::Enable();
+ CrashRecoveryContext CRC;
+ CRC.DumpStackAndCleanupOnFailure = true;
+
const bool Crashed = !CRC.RunSafely([&]() {
for (auto &Map : *DebugMapPtrsOrErr) {
if (Options.LinkOpts.Verbose || Options.DumpDebugMap)
@@ -758,11 +763,13 @@
if (!Options.SymbolMap.empty())
Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map);
- if (Map->begin() == Map->end())
+ if (Map->begin() == Map->end()) {
+ std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
WithColor::warning()
<< "no debug symbols in executable (-arch "
<< MachOUtils::getArchName(Map->getTriple().getArchName())
<< ")\n";
+ }
// Using a std::shared_ptr rather than std::unique_ptr because move-only
// types don't work with std::bind in the ThreadPool implementation.
@@ -774,15 +781,16 @@
auto E = TempFiles.back().createTempFile();
if (E) {
+ std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
WithColor::error() << toString(std::move(E));
AllOK.fetch_and(false);
return;
}
- auto &TempFile = *(TempFiles.back().File);
- OS = std::make_shared<raw_fd_ostream>(TempFile.FD,
+ MachOUtils::ArchAndFile &AF = TempFiles.back();
+ OS = std::make_shared<raw_fd_ostream>(AF.getFD(),
/*shouldClose*/ false);
- OutputFile = TempFile.TmpName;
+ OutputFile = AF.getPath();
} else {
std::error_code EC;
OS = std::make_shared<raw_fd_ostream>(
@@ -804,8 +812,9 @@
if (flagIsSet(Options.Verify, DWARFVerify::Output) ||
(flagIsSet(Options.Verify, DWARFVerify::OutputOnValidInput) &&
!Linker.InputVerificationFailed())) {
- AllOK.fetch_and(verifyOutput(
- OutputFile, Map->getTriple().getArchName(), Options));
+ AllOK.fetch_and(verifyOutput(OutputFile,
+ Map->getTriple().getArchName(),
+ Options, ErrorHandlerMutex));
}
};
@@ -850,7 +859,8 @@
uint64_t FileOffset =
MagicAndCountSize + UniversalArchInfoSize * TempFiles.size();
for (const auto &File : TempFiles) {
- ErrorOr<vfs::Status> stat = Options.LinkOpts.VFS->status(File.path());
+ ErrorOr<vfs::Status> stat =
+ Options.LinkOpts.VFS->status(File.getPath());
if (!stat)
break;
if (FileOffset > UINT32_MAX) {
diff --git a/src/llvm-project/llvm/tools/dsymutil/dsymutil.h b/src/llvm-project/llvm/tools/dsymutil/dsymutil.h
index e679928..5504dd5 100644
--- a/src/llvm-project/llvm/tools/dsymutil/dsymutil.h
+++ b/src/llvm-project/llvm/tools/dsymutil/dsymutil.h
@@ -29,21 +29,20 @@
namespace llvm {
namespace dsymutil {
-class BinaryHolder;
-
/// Extract the DebugMaps from the given file.
/// The file has to be a MachO object file. Multiple debug maps can be
/// returned when the file is universal (aka fat) binary.
ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
- bool InputIsYAML);
+ ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
+ StringRef VariantSuffix, bool Verbose, bool InputIsYAML);
/// Dump the symbol table.
bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath = "");
+ ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath = "",
+ StringRef VariantSuffix = "");
} // end namespace dsymutil
} // end namespace llvm
diff --git a/src/llvm-project/llvm/tools/gold/gold-plugin.cpp b/src/llvm-project/llvm/tools/gold/gold-plugin.cpp
index a47dba3..257832a 100644
--- a/src/llvm-project/llvm/tools/gold/gold-plugin.cpp
+++ b/src/llvm-project/llvm/tools/gold/gold-plugin.cpp
@@ -308,8 +308,6 @@
RemarksFormat = std::string(opt);
} else if (opt.consume_front("stats-file=")) {
stats_file = std::string(opt);
- } else if (opt == "opaque-pointers") {
- // We always use opaque pointers.
} else {
// Save this option to pass to the code generator.
// ParseCommandLineOptions() expects argv[0] to be program name. Lazily
@@ -538,14 +536,6 @@
BufferRef = Buffer->getMemBufferRef();
}
- // Only use bitcode files for LTO. InputFile::create() will load bitcode
- // from the .llvmbc section within a binary object, this bitcode is typically
- // generated by -fembed-bitcode and is not to be used by LLVMgold.so for LTO.
- if (identify_magic(BufferRef.getBuffer()) != file_magic::bitcode) {
- *claimed = 0;
- return LDPS_OK;
- }
-
*claimed = 1;
Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
@@ -878,7 +868,7 @@
Conf.MAttrs = codegen::getMAttrs();
Conf.RelocModel = RelocationModel;
Conf.CodeModel = codegen::getExplicitCodeModel();
- std::optional<CodeGenOpt::Level> CGOptLevelOrNone =
+ std::optional<CodeGenOptLevel> CGOptLevelOrNone =
CodeGenOpt::getLevel(options::OptLevel);
assert(CGOptLevelOrNone && "Invalid optimization level");
Conf.CGOptLevel = *CGOptLevelOrNone;
@@ -934,7 +924,8 @@
/* UseInputModulePath */ true));
break;
case options::OT_ASM_ONLY:
- Conf.CGFileType = CGFT_AssemblyFile;
+ Conf.CGFileType = CodeGenFileType::AssemblyFile;
+ Conf.Options.MCOptions.AsmVerbose = true;
break;
}
diff --git a/src/llvm-project/llvm/tools/llc/CMakeLists.txt b/src/llvm-project/llvm/tools/llc/CMakeLists.txt
index 257d5b5..01825c6 100644
--- a/src/llvm-project/llvm/tools/llc/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llc/CMakeLists.txt
@@ -8,9 +8,11 @@
CodeGen
CodeGenTypes
Core
+ IRPrinter
IRReader
MC
MIRParser
+ Passes
Remarks
ScalarOpts
SelectionDAG
@@ -23,6 +25,7 @@
add_llvm_tool(llc
llc.cpp
+ NewPMDriver.cpp
DEPENDS
intrinsics_gen
diff --git a/src/llvm-project/llvm/tools/llc/NewPMDriver.cpp b/src/llvm-project/llvm/tools/llc/NewPMDriver.cpp
new file mode 100644
index 0000000..13020f3
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llc/NewPMDriver.cpp
@@ -0,0 +1,236 @@
+//===- NewPMDriver.cpp - Driver for llc using new PM ----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file is just a split of the code that logically belongs in llc.cpp but
+/// that includes the new pass manager headers.
+///
+//===----------------------------------------------------------------------===//
+
+#include "NewPMDriver.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/CodeGen/CodeGenPassBuilder.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MIRPrinter.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/IRPrintingPasses.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/StandardInstrumentations.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Target/CGPassBuilderOption.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+extern cl::opt<bool> PrintPipelinePasses;
+} // namespace llvm
+
+using namespace llvm;
+
+static cl::opt<std::string>
+ RegAlloc("regalloc-npm",
+ cl::desc("Register allocator to use for new pass manager"),
+ cl::Hidden, cl::init("default"));
+
+static cl::opt<bool>
+ DebugPM("debug-pass-manager", cl::Hidden,
+ cl::desc("Print pass management debugging information"));
+
+bool LLCDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) {
+ DiagnosticHandler::handleDiagnostics(DI);
+ if (DI.getKind() == llvm::DK_SrcMgr) {
+ const auto &DISM = cast<DiagnosticInfoSrcMgr>(DI);
+ const SMDiagnostic &SMD = DISM.getSMDiag();
+
+ SMD.print(nullptr, errs());
+
+ // For testing purposes, we print the LocCookie here.
+ if (DISM.isInlineAsmDiag() && DISM.getLocCookie())
+ WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n";
+
+ return true;
+ }
+
+ if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
+ if (!Remark->isEnabled())
+ return true;
+
+ DiagnosticPrinterRawOStream DP(errs());
+ errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
+ DI.print(DP);
+ errs() << "\n";
+ return true;
+}
+
+static llvm::ExitOnError ExitOnErr;
+
+static void RunPasses(bool BOS, ToolOutputFile *Out, Module *M,
+ LLVMContext &Context, SmallString<0> &Buffer,
+ ModulePassManager *MPM, ModuleAnalysisManager *MAM,
+ MachineFunctionPassManager &MFPM,
+ MachineFunctionAnalysisManager &MFAM) {
+ assert(M && "invalid input module!");
+
+ // Before executing passes, print the final values of the LLVM options.
+ cl::PrintOptionValues();
+
+ if (MPM) {
+ assert(MAM && "expect a ModuleAnalysisManager!");
+ MPM->run(*M, *MAM);
+ }
+
+ ExitOnErr(MFPM.run(*M, MFAM));
+
+ if (Context.getDiagHandlerPtr()->HasErrors)
+ exit(1);
+
+ if (BOS)
+ Out->os() << Buffer;
+}
+
+int llvm::compileModuleWithNewPM(
+ StringRef Arg0, std::unique_ptr<Module> M, std::unique_ptr<MIRParser> MIR,
+ std::unique_ptr<TargetMachine> Target, std::unique_ptr<ToolOutputFile> Out,
+ std::unique_ptr<ToolOutputFile> DwoOut, LLVMContext &Context,
+ const TargetLibraryInfoImpl &TLII, bool NoVerify, StringRef PassPipeline,
+ CodeGenFileType FileType) {
+
+ if (!PassPipeline.empty() && TargetPassConfig::hasLimitedCodeGenPipeline()) {
+ WithColor::warning(errs(), Arg0)
+ << "--passes cannot be used with "
+ << TargetPassConfig::getLimitedCodeGenPipelineReason() << ".\n";
+ return 1;
+ }
+
+ LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine &>(*Target);
+
+ raw_pwrite_stream *OS = &Out->os();
+
+ // Manually do the buffering rather than using buffer_ostream,
+ // so we can memcmp the contents in CompileTwice mode in future.
+ SmallString<0> Buffer;
+ std::unique_ptr<raw_svector_ostream> BOS;
+ if ((codegen::getFileType() != CodeGenFileType::AssemblyFile &&
+ !Out->os().supportsSeeking())) {
+ BOS = std::make_unique<raw_svector_ostream>(Buffer);
+ OS = BOS.get();
+ }
+
+ // Fetch options from TargetPassConfig
+ CGPassBuilderOption Opt = getCGPassBuilderOption();
+ Opt.DisableVerify = NoVerify;
+ Opt.DebugPM = DebugPM;
+ Opt.RegAlloc = RegAlloc;
+
+ PassInstrumentationCallbacks PIC;
+ StandardInstrumentations SI(Context, Opt.DebugPM);
+ SI.registerCallbacks(PIC);
+ registerCodeGenCallback(PIC, LLVMTM);
+
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+ PassBuilder PB(Target.get(), PipelineTuningOptions(), std::nullopt, &PIC);
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
+ MAM.registerPass([&] { return MachineModuleAnalysis(&LLVMTM); });
+
+ MachineFunctionAnalysisManager MFAM(FAM, MAM);
+
+ if (!PassPipeline.empty()) {
+ // Construct a custom pass pipeline that starts after instruction
+ // selection.
+
+ if (!MIR) {
+ WithColor::warning(errs(), Arg0) << "-passes is for .mir file only.\n";
+ return 1;
+ }
+
+ MachineFunctionPassManager MFPM;
+ ExitOnErr(PB.parsePassPipeline(MFPM, PassPipeline));
+ MFPM.addPass(PrintMIRPass(*OS));
+ MFPM.addPass(FreeMachineFunctionPass());
+
+ auto &MMI = MFAM.getResult<MachineModuleAnalysis>(*M);
+ if (MIR->parseMachineFunctions(*M, MMI))
+ return 1;
+
+ RunPasses(BOS.get(), Out.get(), M.get(), Context, Buffer, nullptr, nullptr,
+ MFPM, MFAM);
+ } else {
+ ModulePassManager MPM;
+ MachineFunctionPassManager MFPM;
+
+ ExitOnErr(LLVMTM.buildCodeGenPipeline(MPM, MFPM, MFAM, *OS,
+ DwoOut ? &DwoOut->os() : nullptr,
+ FileType, Opt, &PIC));
+
+ auto StartStopInfo = TargetPassConfig::getStartStopInfo(PIC);
+ assert(StartStopInfo && "Expect StartStopInfo!");
+ // Add IR or MIR printing pass according the pass type.
+
+ if (auto StopPassName = StartStopInfo->StopPass; !StopPassName.empty()) {
+ MFPM.addPass(PrintMIRPass(*OS));
+ MFPM.addPass(FreeMachineFunctionPass());
+ }
+
+ if (PrintPipelinePasses) {
+ std::string IRPipeline;
+ raw_string_ostream IRSOS(IRPipeline);
+ MPM.printPipeline(IRSOS, [&PIC](StringRef ClassName) {
+ auto PassName = PIC.getPassNameForClassName(ClassName);
+ return PassName.empty() ? ClassName : PassName;
+ });
+ outs() << "IR pipeline: " << IRPipeline << '\n';
+
+ std::string MIRPipeline;
+ raw_string_ostream MIRSOS(MIRPipeline);
+ MFPM.printPipeline(MIRSOS, [&PIC](StringRef ClassName) {
+ auto PassName = PIC.getPassNameForClassName(ClassName);
+ return PassName.empty() ? ClassName : PassName;
+ });
+ outs() << "MIR pipeline: " << MIRPipeline << '\n';
+ return 0;
+ }
+
+ RunPasses(BOS.get(), Out.get(), M.get(), Context, Buffer, &MPM, &MAM, MFPM,
+ MFAM);
+ }
+
+ // Declare success.
+ Out->keep();
+ if (DwoOut)
+ DwoOut->keep();
+
+ return 0;
+}
diff --git a/src/llvm-project/llvm/tools/llc/NewPMDriver.h b/src/llvm-project/llvm/tools/llc/NewPMDriver.h
new file mode 100644
index 0000000..b0beeaf
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llc/NewPMDriver.h
@@ -0,0 +1,49 @@
+//===- NewPMDriver.h - Function to drive llc with the new PM ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// A single function which is called to drive the llc behavior for the new
+/// PassManager.
+///
+/// This is only in a separate TU with a header to avoid including all of the
+/// old pass manager headers and the new pass manager headers into the same
+/// file. Eventually all of the routines here will get folded back into
+/// llc.cpp.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_LLC_NEWPMDRIVER_H
+#define LLVM_TOOLS_LLC_NEWPMDRIVER_H
+
+#include "llvm/IR/DiagnosticHandler.h"
+#include "llvm/Support/CodeGen.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+class Module;
+class TargetLibraryInfoImpl;
+class TargetMachine;
+class ToolOutputFile;
+class LLVMContext;
+class MIRParser;
+
+struct LLCDiagnosticHandler : public DiagnosticHandler {
+ bool handleDiagnostics(const DiagnosticInfo &DI) override;
+};
+
+int compileModuleWithNewPM(StringRef Arg0, std::unique_ptr<Module> M,
+ std::unique_ptr<MIRParser> MIR,
+ std::unique_ptr<TargetMachine> Target,
+ std::unique_ptr<ToolOutputFile> Out,
+ std::unique_ptr<ToolOutputFile> DwoOut,
+ LLVMContext &Context,
+ const TargetLibraryInfoImpl &TLII, bool NoVerify,
+ StringRef PassPipeline, CodeGenFileType FileType);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llc/llc.cpp b/src/llvm-project/llvm/tools/llc/llc.cpp
index 8934130..3e2567c 100644
--- a/src/llvm-project/llvm/tools/llc/llc.cpp
+++ b/src/llvm-project/llvm/tools/llc/llc.cpp
@@ -7,11 +7,12 @@
//===----------------------------------------------------------------------===//
//
// This is the llc code generator driver. It provides a convenient
-// command-line interface for generating native assembly-language code
-// or C code, given LLVM bitcode.
+// command-line interface for generating an assembly file or a relocatable file,
+// given LLVM bitcode.
//
//===----------------------------------------------------------------------===//
+#include "NewPMDriver.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
@@ -186,6 +187,28 @@
cl::desc("The format used for serializing remarks (default: YAML)"),
cl::value_desc("format"), cl::init("yaml"));
+static cl::opt<bool> EnableNewPassManager(
+ "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false));
+
+// This flag specifies a textual description of the optimization pass pipeline
+// to run over the module. This flag switches opt to use the new pass manager
+// infrastructure, completely disabling all of the flags specific to the old
+// pass management.
+static cl::opt<std::string> PassPipeline(
+ "passes",
+ cl::desc(
+ "A textual description of the pass pipeline. To have analysis passes "
+ "available before a certain pass, add 'require<foo-analysis>'."));
+static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline),
+ cl::desc("Alias for -passes"));
+
+static cl::opt<bool> TryUseNewDbgInfoFormat(
+ "try-experimental-debuginfo-iterators",
+ cl::desc("Enable debuginfo iterator positions, if they're built in"),
+ cl::init(false), cl::Hidden);
+
+extern cl::opt<bool> UseNewDbgInfoFormat;
+
namespace {
std::vector<std::string> &getRunPassNames() {
@@ -203,7 +226,7 @@
getRunPassNames().push_back(std::string(PassName));
}
};
-}
+} // namespace
static RunPassOption RunPassOpt;
@@ -242,32 +265,24 @@
else {
// If InputFilename ends in .bc or .ll, remove it.
StringRef IFN = InputFilename;
- if (IFN.endswith(".bc") || IFN.endswith(".ll"))
+ if (IFN.ends_with(".bc") || IFN.ends_with(".ll"))
OutputFilename = std::string(IFN.drop_back(3));
- else if (IFN.endswith(".mir"))
+ else if (IFN.ends_with(".mir"))
OutputFilename = std::string(IFN.drop_back(4));
else
OutputFilename = std::string(IFN);
switch (codegen::getFileType()) {
- case CGFT_AssemblyFile:
- if (TargetName[0] == 'c') {
- if (TargetName[1] == 0)
- OutputFilename += ".cbe.c";
- else if (TargetName[1] == 'p' && TargetName[2] == 'p')
- OutputFilename += ".cpp";
- else
- OutputFilename += ".s";
- } else
- OutputFilename += ".s";
+ case CodeGenFileType::AssemblyFile:
+ OutputFilename += ".s";
break;
- case CGFT_ObjectFile:
+ case CodeGenFileType::ObjectFile:
if (OS == Triple::Win32)
OutputFilename += ".obj";
else
OutputFilename += ".o";
break;
- case CGFT_Null:
+ case CodeGenFileType::Null:
OutputFilename = "-";
break;
}
@@ -277,10 +292,10 @@
// Decide if we need "binary" output.
bool Binary = false;
switch (codegen::getFileType()) {
- case CGFT_AssemblyFile:
+ case CodeGenFileType::AssemblyFile:
break;
- case CGFT_ObjectFile:
- case CGFT_Null:
+ case CodeGenFileType::ObjectFile:
+ case CodeGenFileType::Null:
Binary = true;
break;
}
@@ -299,41 +314,6 @@
return FDOut;
}
-struct LLCDiagnosticHandler : public DiagnosticHandler {
- bool *HasError;
- LLCDiagnosticHandler(bool *HasErrorPtr) : HasError(HasErrorPtr) {}
- bool handleDiagnostics(const DiagnosticInfo &DI) override {
- if (DI.getKind() == llvm::DK_SrcMgr) {
- const auto &DISM = cast<DiagnosticInfoSrcMgr>(DI);
- const SMDiagnostic &SMD = DISM.getSMDiag();
-
- if (SMD.getKind() == SourceMgr::DK_Error)
- *HasError = true;
-
- SMD.print(nullptr, errs());
-
- // For testing purposes, we print the LocCookie here.
- if (DISM.isInlineAsmDiag() && DISM.getLocCookie())
- WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n";
-
- return true;
- }
-
- if (DI.getSeverity() == DS_Error)
- *HasError = true;
-
- if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
- if (!Remark->isEnabled())
- return true;
-
- DiagnosticPrinterRawOStream DP(errs());
- errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
- DI.print(DP);
- errs() << "\n";
- return true;
- }
-};
-
// main - Entry point for the llc compiler.
//
int main(int argc, char **argv) {
@@ -377,6 +357,24 @@
cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
+ if (!PassPipeline.empty() && !getRunPassNames().empty()) {
+ errs() << "The `llc -run-pass=...` syntax for the new pass manager is "
+ "not supported, please use `llc -passes=<pipeline>` (or the `-p` "
+ "alias for a more concise version).\n";
+ return 1;
+ }
+
+ // RemoveDIs debug-info transition: tests may request that we /try/ to use the
+ // new debug-info format, if it's built in.
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ if (TryUseNewDbgInfoFormat) {
+ // If LLVM was built with support for this, turn the new debug-info format
+ // on.
+ UseNewDbgInfoFormat = true;
+ }
+#endif
+ (void)TryUseNewDbgInfoFormat;
+
if (TimeTrace)
timeTraceProfilerInitialize(TimeTraceGranularity, argv[0]);
auto TimeTraceScopeExit = make_scope_exit([]() {
@@ -395,9 +393,7 @@
Context.setDiscardValueNames(DiscardValueNames);
// Set a diagnostic handler that doesn't exit on the first error
- bool HasError = false;
- Context.setDiagnosticHandler(
- std::make_unique<LLCDiagnosticHandler>(&HasError));
+ Context.setDiagnosticHandler(std::make_unique<LLCDiagnosticHandler>());
Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr =
setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
@@ -468,7 +464,7 @@
bool SkipModule =
CPUStr == "help" || (!MAttrs.empty() && MAttrs.front() == "help");
- CodeGenOpt::Level OLvl;
+ CodeGenOptLevel OLvl;
if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
OLvl = *Level;
} else {
@@ -558,12 +554,6 @@
exit(1);
}
- // On AIX, setting the relocation model to anything other than PIC is
- // considered a user error.
- if (TheTriple.isOSAIX() && RM && *RM != Reloc::PIC_)
- reportError("invalid relocation model, AIX only supports PIC",
- InputFilename);
-
InitializeOptions(TheTriple);
Target = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
TheTriple.getTriple(), CPUStr, FeaturesStr, Options, RM, CM, OLvl));
@@ -572,7 +562,7 @@
return Target->createDataLayout().getStringRepresentation();
};
if (InputLanguage == "mir" ||
- (InputLanguage == "" && StringRef(InputFilename).endswith(".mir"))) {
+ (InputLanguage == "" && StringRef(InputFilename).ends_with(".mir"))) {
MIR = createMIRParserFromFile(InputFilename, Err, Context,
setMIRFunctionAttributes);
if (MIR)
@@ -591,6 +581,8 @@
std::optional<CodeModel::Model> CM_IR = M->getCodeModel();
if (!CM && CM_IR)
Target->setCodeModel(*CM_IR);
+ if (std::optional<uint64_t> LDT = codegen::getExplicitLargeDataThreshold())
+ Target->setLargeDataThreshold(*LDT);
} else {
TheTriple = Triple(Triple::normalize(TargetTriple));
if (TheTriple.getTriple().empty())
@@ -605,14 +597,6 @@
return 1;
}
- // On AIX, setting the relocation model to anything other than PIC is
- // considered a user error.
- if (TheTriple.isOSAIX() && RM && *RM != Reloc::PIC_) {
- WithColor::error(errs(), argv[0])
- << "invalid relocation model, AIX only supports PIC.\n";
- return 1;
- }
-
InitializeOptions(TheTriple);
Target = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
TheTriple.getTriple(), CPUStr, FeaturesStr, Options, RM, CM, OLvl));
@@ -626,7 +610,7 @@
assert(M && "Should have exited if we didn't have a module!");
if (codegen::getFloatABIForCalls() != FloatABI::Default)
- Options.FloatABIType = codegen::getFloatABIForCalls();
+ Target->Options.FloatABIType = codegen::getFloatABIForCalls();
// Figure out where we are going to send the output.
std::unique_ptr<ToolOutputFile> Out =
@@ -645,16 +629,12 @@
reportError(EC.message(), SplitDwarfOutputFile);
}
- // Build up all of the passes that we want to do to the module.
- legacy::PassManager PM;
-
// Add an appropriate TargetLibraryInfo pass for the module's triple.
TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
// The -disable-simplify-libcalls flag actually disables all builtin optzns.
if (DisableSimplifyLibCalls)
TLII.disableAllFunctions();
- PM.add(new TargetLibraryInfoWrapperPass(TLII));
// Verify module immediately to catch problems before doInitialization() is
// called on any passes.
@@ -665,10 +645,22 @@
// flags.
codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M);
- if (mc::getExplicitRelaxAll() && codegen::getFileType() != CGFT_ObjectFile)
+ if (mc::getExplicitRelaxAll() &&
+ codegen::getFileType() != CodeGenFileType::ObjectFile)
WithColor::warning(errs(), argv[0])
<< ": warning: ignoring -mc-relax-all because filetype != obj";
+ if (EnableNewPassManager || !PassPipeline.empty()) {
+ return compileModuleWithNewPM(argv[0], std::move(M), std::move(MIR),
+ std::move(Target), std::move(Out),
+ std::move(DwoOut), Context, TLII, NoVerify,
+ PassPipeline, codegen::getFileType());
+ }
+
+ // Build up all of the passes that we want to do to the module.
+ legacy::PassManager PM;
+ PM.add(new TargetLibraryInfoWrapperPass(TLII));
+
{
raw_pwrite_stream *OS = &Out->os();
@@ -676,7 +668,7 @@
// so we can memcmp the contents in CompileTwice mode
SmallVector<char, 0> Buffer;
std::unique_ptr<raw_svector_ostream> BOS;
- if ((codegen::getFileType() != CGFT_AssemblyFile &&
+ if ((codegen::getFileType() != CodeGenFileType::AssemblyFile &&
!Out->os().supportsSeeking()) ||
CompileTwice) {
BOS = std::make_unique<raw_svector_ostream>(Buffer);
@@ -702,7 +694,7 @@
if (TPC.hasLimitedCodeGenPipeline()) {
WithColor::warning(errs(), argv[0])
<< "run-pass cannot be used with "
- << TPC.getLimitedCodeGenPipelineReason(" and ") << ".\n";
+ << TPC.getLimitedCodeGenPipelineReason() << ".\n";
delete PTPC;
delete MMIWP;
return 1;
@@ -750,9 +742,7 @@
PM.run(*M);
- auto HasError =
- ((const LLCDiagnosticHandler *)(Context.getDiagHandlerPtr()))->HasError;
- if (*HasError)
+ if (Context.getDiagHandlerPtr()->HasErrors)
return 1;
// Compare the two outputs and make sure they're the same
diff --git a/src/llvm-project/llvm/tools/lli/CMakeLists.txt b/src/llvm-project/llvm/tools/lli/CMakeLists.txt
index 3b3cf91..e3fca22 100644
--- a/src/llvm-project/llvm/tools/lli/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/lli/CMakeLists.txt
@@ -12,8 +12,9 @@
MC
MCJIT
Object
- OrcShared
OrcJIT
+ OrcDebugging
+ OrcShared
OrcTargetProcess
Passes
RuntimeDyld
@@ -52,7 +53,6 @@
add_llvm_tool(lli
lli.cpp
- ExecutionUtils.cpp
DEPENDS
intrinsics_gen
diff --git a/src/llvm-project/llvm/tools/lli/ChildTarget/ChildTarget.cpp b/src/llvm-project/llvm/tools/lli/ChildTarget/ChildTarget.cpp
index cf1b03a..cb81ac5 100644
--- a/src/llvm-project/llvm/tools/lli/ChildTarget/ChildTarget.cpp
+++ b/src/llvm-project/llvm/tools/lli/ChildTarget/ChildTarget.cpp
@@ -10,7 +10,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
diff --git a/src/llvm-project/llvm/tools/lli/ExecutionUtils.cpp b/src/llvm-project/llvm/tools/lli/ExecutionUtils.cpp
deleted file mode 100644
index 55370ed..0000000
--- a/src/llvm-project/llvm/tools/lli/ExecutionUtils.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-//===---- ExecutionUtils.cpp - Utilities for executing functions in lli ---===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExecutionUtils.h"
-
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <cstdint>
-#include <vector>
-
-// Declarations follow the GDB JIT interface (version 1, 2009) and must match
-// those of the DYLD used for testing. See:
-//
-// llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp
-// llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp
-//
-typedef enum {
- JIT_NOACTION = 0,
- JIT_REGISTER_FN,
- JIT_UNREGISTER_FN
-} jit_actions_t;
-
-struct jit_code_entry {
- struct jit_code_entry *next_entry;
- struct jit_code_entry *prev_entry;
- const char *symfile_addr;
- uint64_t symfile_size;
-};
-
-struct jit_descriptor {
- uint32_t version;
- // This should be jit_actions_t, but we want to be specific about the
- // bit-width.
- uint32_t action_flag;
- struct jit_code_entry *relevant_entry;
- struct jit_code_entry *first_entry;
-};
-
-namespace llvm {
-
-template <typename... Ts> static void outsv(const char *Fmt, Ts &&...Vals) {
- outs() << formatv(Fmt, Vals...);
-}
-
-static const char *actionFlagToStr(uint32_t ActionFlag) {
- switch (ActionFlag) {
- case JIT_NOACTION:
- return "JIT_NOACTION";
- case JIT_REGISTER_FN:
- return "JIT_REGISTER_FN";
- case JIT_UNREGISTER_FN:
- return "JIT_UNREGISTER_FN";
- }
- return "<invalid action_flag>";
-}
-
-// Sample output:
-//
-// Reading __jit_debug_descriptor at 0x0000000000404048
-//
-// Version: 0
-// Action: JIT_REGISTER_FN
-//
-// Entry Symbol File Size Previous Entry
-// [ 0] 0x0000000000451290 0x0000000000002000 200 0x0000000000000000
-// [ 1] 0x0000000000451260 0x0000000000001000 100 0x0000000000451290
-// ...
-//
-static void dumpDebugDescriptor(void *Addr) {
- outsv("Reading __jit_debug_descriptor at {0}\n\n", Addr);
-
- jit_descriptor *Descriptor = reinterpret_cast<jit_descriptor *>(Addr);
- outsv("Version: {0}\n", Descriptor->version);
- outsv("Action: {0}\n\n", actionFlagToStr(Descriptor->action_flag));
- outsv("{0,11} {1,24} {2,15} {3,14}\n", "Entry", "Symbol File", "Size",
- "Previous Entry");
-
- unsigned Idx = 0;
- for (auto *Entry = Descriptor->first_entry; Entry; Entry = Entry->next_entry)
- outsv("[{0,2}] {1:X16} {2:X16} {3,8:D} {4}\n", Idx++, Entry,
- reinterpret_cast<const void *>(Entry->symfile_addr),
- Entry->symfile_size, Entry->prev_entry);
-}
-
-static LLIBuiltinFunctionGenerator *Generator = nullptr;
-
-static void dumpDebugObjects(void *Addr) {
- jit_descriptor *Descriptor = reinterpret_cast<jit_descriptor *>(Addr);
- for (auto *Entry = Descriptor->first_entry; Entry; Entry = Entry->next_entry)
- Generator->appendDebugObject(Entry->symfile_addr, Entry->symfile_size);
-}
-
-LLIBuiltinFunctionGenerator::LLIBuiltinFunctionGenerator(
- std::vector<BuiltinFunctionKind> Enabled, orc::MangleAndInterner &Mangle)
- : TestOut(nullptr) {
- Generator = this;
- for (BuiltinFunctionKind F : Enabled) {
- switch (F) {
- case BuiltinFunctionKind::DumpDebugDescriptor:
- expose(Mangle("__dump_jit_debug_descriptor"), &dumpDebugDescriptor);
- break;
- case BuiltinFunctionKind::DumpDebugObjects:
- expose(Mangle("__dump_jit_debug_objects"), &dumpDebugObjects);
- TestOut = createToolOutput();
- break;
- }
- }
-}
-
-Error LLIBuiltinFunctionGenerator::tryToGenerate(
- orc::LookupState &LS, orc::LookupKind K, orc::JITDylib &JD,
- orc::JITDylibLookupFlags JDLookupFlags,
- const orc::SymbolLookupSet &Symbols) {
- orc::SymbolMap NewSymbols;
- for (const auto &NameFlags : Symbols) {
- auto It = BuiltinFunctions.find(NameFlags.first);
- if (It != BuiltinFunctions.end())
- NewSymbols.insert(*It);
- }
-
- if (NewSymbols.empty())
- return Error::success();
-
- return JD.define(absoluteSymbols(std::move(NewSymbols)));
-}
-
-// static
-std::unique_ptr<ToolOutputFile>
-LLIBuiltinFunctionGenerator::createToolOutput() {
- std::error_code EC;
- auto TestOut = std::make_unique<ToolOutputFile>("-", EC, sys::fs::OF_None);
- if (EC) {
- errs() << "Error creating tool output file: " << EC.message() << '\n';
- exit(1);
- }
- return TestOut;
-}
-
-} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/lli/ExecutionUtils.h b/src/llvm-project/llvm/tools/lli/ExecutionUtils.h
deleted file mode 100644
index 6bf9cd5..0000000
--- a/src/llvm-project/llvm/tools/lli/ExecutionUtils.h
+++ /dev/null
@@ -1,60 +0,0 @@
-//===- ExecutionUtils.h - Utilities for executing code in lli ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Contains utilities for executing code in lli.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLI_EXECUTIONUTILS_H
-#define LLVM_TOOLS_LLI_EXECUTIONUTILS_H
-
-#include "llvm/ExecutionEngine/JITSymbol.h"
-#include "llvm/ExecutionEngine/Orc/Core.h"
-#include "llvm/ExecutionEngine/Orc/Mangling.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ToolOutputFile.h"
-
-#include <memory>
-#include <utility>
-
-namespace llvm {
-
-enum class BuiltinFunctionKind {
- DumpDebugDescriptor,
- DumpDebugObjects,
-};
-
-// Utility class to expose symbols for special-purpose functions to the JIT.
-class LLIBuiltinFunctionGenerator : public orc::DefinitionGenerator {
-public:
- LLIBuiltinFunctionGenerator(std::vector<BuiltinFunctionKind> Enabled,
- orc::MangleAndInterner &Mangle);
-
- Error tryToGenerate(orc::LookupState &LS, orc::LookupKind K,
- orc::JITDylib &JD, orc::JITDylibLookupFlags JDLookupFlags,
- const orc::SymbolLookupSet &Symbols) override;
-
- void appendDebugObject(const char *Addr, size_t Size) {
- TestOut->os().write(Addr, Size);
- }
-
-private:
- orc::SymbolMap BuiltinFunctions;
- std::unique_ptr<ToolOutputFile> TestOut;
-
- template <typename T> void expose(orc::SymbolStringPtr Name, T *Handler) {
- BuiltinFunctions[Name] = {orc::ExecutorAddr::fromPtr(Handler),
- JITSymbolFlags::Exported};
- }
-
- static std::unique_ptr<ToolOutputFile> createToolOutput();
-};
-
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_LLI_EXECUTIONUTILS_H
diff --git a/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h b/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h
index f1de7a1..2cc6699 100644
--- a/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h
+++ b/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h
@@ -105,13 +105,14 @@
JITSymbol findSymbol(const std::string &Name) override {
orc::RemoteSymbolLookupSet R;
R.push_back({std::move(Name), false});
- if (auto Addrs = DylibMgr.lookup(H, R)) {
- if (Addrs->size() != 1)
+ if (auto Syms = DylibMgr.lookup(H, R)) {
+ if (Syms->size() != 1)
return make_error<StringError>("Unexpected remote lookup result",
inconvertibleErrorCode());
- return JITSymbol(Addrs->front().getValue(), JITSymbolFlags::Exported);
+ return JITSymbol(Syms->front().getAddress().getValue(),
+ Syms->front().getFlags());
} else
- return Addrs.takeError();
+ return Syms.takeError();
}
JITSymbol findSymbolInLogicalDylib(const std::string &Name) override {
diff --git a/src/llvm-project/llvm/tools/lli/lli.cpp b/src/llvm-project/llvm/tools/lli/lli.cpp
index e2fff69..905ec23 100644
--- a/src/llvm-project/llvm/tools/lli/lli.cpp
+++ b/src/llvm-project/llvm/tools/lli/lli.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "ExecutionUtils.h"
#include "ForwardingMemoryManager.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitcodeReader.h"
@@ -26,12 +25,14 @@
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
@@ -61,6 +62,7 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
@@ -253,35 +255,29 @@
NoDump,
DumpFuncsToStdOut,
DumpModsToStdOut,
- DumpModsToDisk
+ DumpModsToDisk,
+ DumpDebugDescriptor,
+ DumpDebugObjects,
};
cl::opt<DumpKind> OrcDumpKind(
"orc-lazy-debug", cl::desc("Debug dumping for the orc-lazy JIT."),
cl::init(DumpKind::NoDump),
- cl::values(clEnumValN(DumpKind::NoDump, "no-dump",
- "Don't dump anything."),
- clEnumValN(DumpKind::DumpFuncsToStdOut, "funcs-to-stdout",
- "Dump function names to stdout."),
- clEnumValN(DumpKind::DumpModsToStdOut, "mods-to-stdout",
- "Dump modules to stdout."),
- clEnumValN(DumpKind::DumpModsToDisk, "mods-to-disk",
- "Dump modules to the current "
- "working directory. (WARNING: "
- "will overwrite existing files).")),
- cl::Hidden);
-
- cl::list<BuiltinFunctionKind> GenerateBuiltinFunctions(
- "generate",
- cl::desc("Provide built-in functions for access by JITed code "
- "(jit-kind=orc-lazy only)"),
- cl::values(clEnumValN(BuiltinFunctionKind::DumpDebugDescriptor,
- "__dump_jit_debug_descriptor",
- "Dump __jit_debug_descriptor contents to stdout"),
- clEnumValN(BuiltinFunctionKind::DumpDebugObjects,
- "__dump_jit_debug_objects",
- "Dump __jit_debug_descriptor in-memory debug "
- "objects as tool output")),
+ cl::values(
+ clEnumValN(DumpKind::NoDump, "no-dump", "Don't dump anything."),
+ clEnumValN(DumpKind::DumpFuncsToStdOut, "funcs-to-stdout",
+ "Dump function names to stdout."),
+ clEnumValN(DumpKind::DumpModsToStdOut, "mods-to-stdout",
+ "Dump modules to stdout."),
+ clEnumValN(DumpKind::DumpModsToDisk, "mods-to-disk",
+ "Dump modules to the current "
+ "working directory. (WARNING: "
+ "will overwrite existing files)."),
+ clEnumValN(DumpKind::DumpDebugDescriptor, "jit-debug-descriptor",
+ "Dump __jit_debug_descriptor contents to stdout"),
+ clEnumValN(DumpKind::DumpDebugObjects, "jit-debug-objects",
+ "Dump __jit_debug_descriptor in-memory debug "
+ "objects as tool output")),
cl::Hidden);
ExitOnError ExitOnErr;
@@ -405,7 +401,7 @@
EE.addModule(std::move(M));
}
-CodeGenOpt::Level getOptLevel() {
+CodeGenOptLevel getOptLevel() {
if (auto Level = CodeGenOpt::parseLevel(OptLevel))
return *Level;
WithColor::error(errs(), "lli") << "invalid optimization level.\n";
@@ -446,7 +442,13 @@
ExitOnErr(loadDylibs());
- if (UseJITKind == JITKind::MCJIT)
+ if (EntryFunc.empty()) {
+ WithColor::error(errs(), argv[0])
+ << "--entry-function name cannot be empty\n";
+ exit(1);
+ }
+
+ if (UseJITKind == JITKind::MCJIT || ForceInterpreter)
disallowOrcOptions();
else
return runOrcJIT(argv[0]);
@@ -615,7 +617,7 @@
} else {
// Otherwise, if there is a .bc suffix on the executable strip it off, it
// might confuse the program.
- if (StringRef(InputFile).endswith(".bc"))
+ if (StringRef(InputFile).ends_with(".bc"))
InputFile.erase(InputFile.length() - 3);
}
@@ -749,9 +751,41 @@
return Result;
}
-static std::function<void(Module &)> createDebugDumper() {
+// JITLink debug support plugins put information about JITed code in this GDB
+// JIT Interface global from OrcTargetProcess.
+extern "C" struct jit_descriptor __jit_debug_descriptor;
+
+static struct jit_code_entry *
+findNextDebugDescriptorEntry(struct jit_code_entry *Latest) {
+ if (Latest == nullptr)
+ return __jit_debug_descriptor.first_entry;
+ if (Latest->next_entry)
+ return Latest->next_entry;
+ return nullptr;
+}
+
+static ToolOutputFile &claimToolOutput() {
+ static std::unique_ptr<ToolOutputFile> ToolOutput = nullptr;
+ if (ToolOutput) {
+ WithColor::error(errs(), "lli")
+ << "Can not claim stdout for tool output twice\n";
+ exit(1);
+ }
+ std::error_code EC;
+ ToolOutput = std::make_unique<ToolOutputFile>("-", EC, sys::fs::OF_None);
+ if (EC) {
+ WithColor::error(errs(), "lli")
+ << "Failed to create tool output file: " << EC.message() << "\n";
+ exit(1);
+ }
+ return *ToolOutput;
+}
+
+static std::function<void(Module &)> createIRDebugDumper() {
switch (OrcDumpKind) {
case DumpKind::NoDump:
+ case DumpKind::DumpDebugDescriptor:
+ case DumpKind::DumpDebugObjects:
return [](Module &M) {};
case DumpKind::DumpFuncsToStdOut:
@@ -793,6 +827,43 @@
llvm_unreachable("Unknown DumpKind");
}
+static std::function<void(MemoryBuffer &)> createObjDebugDumper() {
+ switch (OrcDumpKind) {
+ case DumpKind::NoDump:
+ case DumpKind::DumpFuncsToStdOut:
+ case DumpKind::DumpModsToStdOut:
+ case DumpKind::DumpModsToDisk:
+ return [](MemoryBuffer &) {};
+
+ case DumpKind::DumpDebugDescriptor: {
+ // Dump the empty descriptor at startup once
+ fprintf(stderr, "jit_debug_descriptor 0x%016" PRIx64 "\n",
+ pointerToJITTargetAddress(__jit_debug_descriptor.first_entry));
+ return [](MemoryBuffer &) {
+ // Dump new entries as they appear
+ static struct jit_code_entry *Latest = nullptr;
+ while (auto *NewEntry = findNextDebugDescriptorEntry(Latest)) {
+ fprintf(stderr, "jit_debug_descriptor 0x%016" PRIx64 "\n",
+ pointerToJITTargetAddress(NewEntry));
+ Latest = NewEntry;
+ }
+ };
+ }
+
+ case DumpKind::DumpDebugObjects: {
+ return [](MemoryBuffer &Obj) {
+ static struct jit_code_entry *Latest = nullptr;
+ static ToolOutputFile &ToolOutput = claimToolOutput();
+ while (auto *NewEntry = findNextDebugDescriptorEntry(Latest)) {
+ ToolOutput.os().write(NewEntry->symfile_addr, NewEntry->symfile_size);
+ Latest = NewEntry;
+ }
+ };
+ }
+ }
+ llvm_unreachable("Unknown DumpKind");
+}
+
Error loadDylibs() {
for (const auto &Dylib : Dylibs) {
std::string ErrMsg;
@@ -838,6 +909,17 @@
return 0;
}
+// Try to enable debugger support for the given instance.
+// This alway returns success, but prints a warning if it's not able to enable
+// debugger support.
+Error tryEnableDebugSupport(orc::LLJIT &J) {
+ if (auto Err = enableDebuggerSupport(J)) {
+ [[maybe_unused]] std::string ErrMsg = toString(std::move(Err));
+ LLVM_DEBUG(dbgs() << "lli: " << ErrMsg << "\n");
+ }
+ return Error::success();
+}
+
int runOrcJIT(const char *ProgName) {
// Start setting up the JIT environment.
@@ -918,6 +1000,9 @@
});
}
+ // Enable debugging of JIT'd code (only works on JITLink for ELF and MachO).
+ Builder.setPrePlatformSetup(tryEnableDebugSupport);
+
// Set up LLJIT platform.
LLJITPlatform P = Platform;
if (P == LLJITPlatform::Auto)
@@ -944,9 +1029,12 @@
EPC = ExitOnErr(orc::SelfExecutorProcessControl::Create(
std::make_shared<orc::SymbolStringPool>()));
- Builder.setObjectLinkingLayerCreator([&EPC, &P](orc::ExecutionSession &ES,
- const Triple &TT) {
- auto L = std::make_unique<orc::ObjectLinkingLayer>(ES, EPC->getMemMgr());
+ Builder.getJITTargetMachineBuilder()
+ ->setRelocationModel(Reloc::PIC_)
+ .setCodeModel(CodeModel::Small);
+ Builder.setObjectLinkingLayerCreator([&P](orc::ExecutionSession &ES,
+ const Triple &TT) {
+ auto L = std::make_unique<orc::ObjectLinkingLayer>(ES);
if (P != LLJITPlatform::ExecutorNative)
L->addPlugin(std::make_unique<orc::EHFrameRegistrationPlugin>(
ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES))));
@@ -954,9 +1042,6 @@
});
}
- // Enable debugging of JIT'd code (only works on JITLink for ELF and MachO).
- Builder.setEnableDebuggerSupport(true);
-
auto J = ExitOnErr(Builder.create());
auto *ObjLayer = &J->getObjLinkingLayer();
@@ -980,8 +1065,7 @@
if (PerModuleLazy)
J->setPartitionFunction(orc::CompileOnDemandLayer::compileWholeModule);
- auto Dump = createDebugDumper();
-
+ auto IRDump = createIRDebugDumper();
J->getIRTransformLayer().setTransform(
[&](orc::ThreadSafeModule TSM,
const orc::MaterializationResponsibility &R) {
@@ -990,18 +1074,18 @@
dbgs() << "Bad module: " << &M << "\n";
exit(1);
}
- Dump(M);
+ IRDump(M);
});
return TSM;
});
- if (GenerateBuiltinFunctions.size() > 0) {
- // Add LLI builtins.
- orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout());
- J->getMainJITDylib().addGenerator(
- std::make_unique<LLIBuiltinFunctionGenerator>(GenerateBuiltinFunctions,
- Mangle));
- }
+ auto ObjDump = createObjDebugDumper();
+ J->getObjTransformLayer().setTransform(
+ [&](std::unique_ptr<MemoryBuffer> Obj)
+ -> Expected<std::unique_ptr<MemoryBuffer>> {
+ ObjDump(*Obj);
+ return std::move(Obj);
+ });
// If this is a Mingw or Cygwin executor then we need to alias __main to
// orc_rt_int_void_return_0.
diff --git a/src/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp b/src/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp
index d21650d..c880030 100644
--- a/src/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -25,7 +25,6 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -69,7 +68,9 @@
<< " -v --version - Display the version of this program\n"
<< " -D - Use zero for timestamps and uids/gids "
"(default)\n"
- << " -U - Use actual timestamps and uids/gids\n";
+ << " -U - Use actual timestamps and uids/gids\n"
+ << " -X{32|64|32_64|any} - Specify which archive symbol tables "
+ "should be generated if they do not already exist (AIX OS only)\n";
}
static void printArHelp(StringRef ToolName) {
@@ -225,7 +226,8 @@
static bool CompareFullPath = false; ///< 'P' modifier
static bool OnlyUpdate = false; ///< 'u' modifier
static bool Verbose = false; ///< 'v' modifier
-static bool Symtab = true; ///< 's' modifier
+static SymtabWritingMode Symtab =
+ SymtabWritingMode::NormalSymtab; ///< 's' modifier
static bool Deterministic = true; ///< 'D' and 'U' modifiers
static bool Thin = false; ///< 'T' modifier
static bool AddLibrary = false; ///< 'L' modifier
@@ -371,11 +373,11 @@
CompareFullPath = true;
break;
case 's':
- Symtab = true;
+ Symtab = SymtabWritingMode::NormalSymtab;
MaybeJustCreateSymTab = true;
break;
case 'S':
- Symtab = false;
+ Symtab = SymtabWritingMode::NoSymtab;
break;
case 'u':
OnlyUpdate = true;
@@ -1074,9 +1076,31 @@
// In summary, we only need to update the symbol table if we have none.
// This is actually very common because of broken build systems that think
// they have to run ranlib.
- if (OldArchive->hasSymbolTable())
- return;
+ if (OldArchive->hasSymbolTable()) {
+ if (OldArchive->kind() != object::Archive::K_AIXBIG)
+ return;
+ // For archives in the Big Archive format, the bit mode option specifies
+ // which symbol table to generate. The presence of a symbol table that does
+ // not match the specified bit mode does not prevent creation of the symbol
+ // table that has been requested.
+ if (OldArchive->kind() == object::Archive::K_AIXBIG) {
+ BigArchive *BigArc = dyn_cast<BigArchive>(OldArchive);
+ if (BigArc->has32BitGlobalSymtab() &&
+ Symtab == SymtabWritingMode::BigArchive32)
+ return;
+
+ if (BigArc->has64BitGlobalSymtab() &&
+ Symtab == SymtabWritingMode::BigArchive64)
+ return;
+
+ if (BigArc->has32BitGlobalSymtab() && BigArc->has64BitGlobalSymtab() &&
+ Symtab == SymtabWritingMode::NormalSymtab)
+ return;
+
+ Symtab = SymtabWritingMode::NormalSymtab;
+ }
+ }
if (OldArchive->isThin())
Thin = true;
performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
@@ -1262,8 +1286,7 @@
ArrayRef<const char *> Args) {
StringRef Arg = *ArgIt;
- if (Arg.startswith("--"))
- Arg = Arg.substr(2);
+ Arg.consume_front("--");
size_t len = Expected.size();
if (Arg == Expected) {
@@ -1272,7 +1295,7 @@
return *ArgIt;
}
- if (Arg.startswith(Expected) && Arg.size() > len && Arg[len] == '=')
+ if (Arg.starts_with(Expected) && Arg.size() > len && Arg[len] == '=')
return Arg.data() + len + 1;
return nullptr;
@@ -1389,6 +1412,8 @@
static int ranlib_main(int argc, char **argv) {
std::vector<StringRef> Archives;
+ bool HasAIXXOption = false;
+
for (int i = 1; i < argc; ++i) {
StringRef arg(argv[i]);
if (handleGenericOption(arg)) {
@@ -1406,6 +1431,28 @@
} else if (arg.front() == 'v') {
cl::PrintVersionMessage();
return 0;
+ } else if (arg.front() == 'X') {
+ if (object::Archive::getDefaultKindForHost() ==
+ object::Archive::K_AIXBIG) {
+ HasAIXXOption = true;
+ arg.consume_front("X");
+ const char *Xarg = arg.data();
+ if (Xarg[0] == '\0') {
+ if (argv[i + 1][0] != '-')
+ BitMode = getBitMode(argv[++i]);
+ else
+ BitMode = BitModeTy::Unknown;
+ } else
+ BitMode = getBitMode(arg.data());
+
+ if (BitMode == BitModeTy::Unknown)
+ fail("the specified object mode is not valid. Specify -X32, "
+ "-X64, -X32_64, or -Xany");
+ } else {
+ fail(Twine("-") + Twine(arg) +
+ " option not supported on non AIX OS");
+ }
+ break;
} else {
// TODO: GNU ranlib also supports a -t flag
fail("Invalid option: '-" + arg + "'");
@@ -1417,6 +1464,31 @@
}
}
+ if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) {
+ // If not specify -X option, get BitMode from enviorment variable
+ // "OBJECT_MODE" for AIX OS if specify.
+ if (!HasAIXXOption) {
+ if (char *EnvObjectMode = getenv("OBJECT_MODE")) {
+ BitMode = getBitMode(EnvObjectMode);
+ if (BitMode == BitModeTy::Unknown)
+ fail("the OBJECT_MODE environment variable has an invalid value. "
+ "OBJECT_MODE must be 32, 64, 32_64, or any");
+ }
+ }
+
+ switch (BitMode) {
+ case BitModeTy::Bit32:
+ Symtab = SymtabWritingMode::BigArchive32;
+ break;
+ case BitModeTy::Bit64:
+ Symtab = SymtabWritingMode::BigArchive64;
+ break;
+ default:
+ Symtab = SymtabWritingMode::NormalSymtab;
+ break;
+ }
+ }
+
for (StringRef Archive : Archives) {
ArchiveName = Archive.str();
performOperation(CreateSymTab);
@@ -1427,7 +1499,6 @@
}
int llvm_ar_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
ToolName = argv[0];
llvm::InitializeAllTargetInfos();
diff --git a/src/llvm-project/llvm/tools/llvm-as/llvm-as.cpp b/src/llvm-project/llvm/tools/llvm-as/llvm-as.cpp
index ef1c50f..1c869e1 100644
--- a/src/llvm-project/llvm/tools/llvm-as/llvm-as.cpp
+++ b/src/llvm-project/llvm/tools/llvm-as/llvm-as.cpp
@@ -75,7 +75,7 @@
OutputFilename = "-";
} else {
StringRef IFN = InputFilename;
- OutputFilename = (IFN.endswith(".ll") ? IFN.drop_back(3) : IFN).str();
+ OutputFilename = (IFN.ends_with(".ll") ? IFN.drop_back(3) : IFN).str();
OutputFilename += ".bc";
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-c-test/echo.cpp b/src/llvm-project/llvm/tools/llvm-c-test/echo.cpp
index b0535c7..bc708e2 100644
--- a/src/llvm-project/llvm/tools/llvm-c-test/echo.cpp
+++ b/src/llvm-project/llvm/tools/llvm-c-test/echo.cpp
@@ -406,6 +406,32 @@
}
}
+static LLVMValueRef clone_inline_asm(LLVMValueRef Asm, LLVMModuleRef M) {
+
+ if (!LLVMIsAInlineAsm(Asm))
+ report_fatal_error("Expected inline assembly");
+
+ size_t AsmStringSize = 0;
+ const char *AsmString = LLVMGetInlineAsmAsmString(Asm, &AsmStringSize);
+
+ size_t ConstraintStringSize = 0;
+ const char *ConstraintString =
+ LLVMGetInlineAsmConstraintString(Asm, &ConstraintStringSize);
+
+ LLVMInlineAsmDialect AsmDialect = LLVMGetInlineAsmDialect(Asm);
+
+ LLVMTypeRef AsmFunctionType = LLVMGetInlineAsmFunctionType(Asm);
+
+ LLVMBool HasSideEffects = LLVMGetInlineAsmHasSideEffects(Asm);
+ LLVMBool NeedsAlignStack = LLVMGetInlineAsmNeedsAlignedStack(Asm);
+ LLVMBool CanUnwind = LLVMGetInlineAsmCanUnwind(Asm);
+
+ return LLVMGetInlineAsm(AsmFunctionType, AsmString, AsmStringSize,
+ ConstraintString, ConstraintStringSize,
+ HasSideEffects, NeedsAlignStack, AsmDialect,
+ CanUnwind);
+}
+
struct FunCloner {
LLVMValueRef Fun;
LLVMModuleRef M;
@@ -435,6 +461,10 @@
if (i != VMap.end())
return i->second;
+ // Inline assembly is a Value, but not an Instruction
+ if (LLVMIsAInlineAsm(Src))
+ return clone_inline_asm(Src, M);
+
if (!LLVMIsAInstruction(Src))
report_fatal_error("Expected an instruction");
@@ -518,16 +548,26 @@
break;
case LLVMInvoke: {
SmallVector<LLVMValueRef, 8> Args;
- int ArgCount = LLVMGetNumArgOperands(Src);
- for (int i = 0; i < ArgCount; i++)
+ SmallVector<LLVMOperandBundleRef, 8> Bundles;
+ unsigned ArgCount = LLVMGetNumArgOperands(Src);
+ for (unsigned i = 0; i < ArgCount; ++i)
Args.push_back(CloneValue(LLVMGetOperand(Src, i)));
+ unsigned BundleCount = LLVMGetNumOperandBundles(Src);
+ for (unsigned i = 0; i < BundleCount; ++i) {
+ auto Bundle = LLVMGetOperandBundleAtIndex(Src, i);
+ Bundles.push_back(CloneOB(Bundle));
+ LLVMDisposeOperandBundle(Bundle);
+ }
LLVMTypeRef FnTy = CloneType(LLVMGetCalledFunctionType(Src));
LLVMValueRef Fn = CloneValue(LLVMGetCalledValue(Src));
LLVMBasicBlockRef Then = DeclareBB(LLVMGetNormalDest(Src));
LLVMBasicBlockRef Unwind = DeclareBB(LLVMGetUnwindDest(Src));
- Dst = LLVMBuildInvoke2(Builder, FnTy, Fn, Args.data(), ArgCount,
- Then, Unwind, Name);
+ Dst = LLVMBuildInvokeWithOperandBundles(
+ Builder, FnTy, Fn, Args.data(), ArgCount, Then, Unwind,
+ Bundles.data(), Bundles.size(), Name);
CloneAttrs(Src, Dst);
+ for (auto Bundle : Bundles)
+ LLVMDisposeOperandBundle(Bundle);
break;
}
case LLVMUnreachable:
@@ -626,7 +666,9 @@
case LLVMOr: {
LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ LLVMBool IsDisjoint = LLVMGetIsDisjoint(Src);
Dst = LLVMBuildOr(Builder, LHS, RHS, Name);
+ LLVMSetIsDisjoint(Dst, IsDisjoint);
break;
}
case LLVMXor: {
@@ -647,6 +689,7 @@
LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
+ LLVMSetAtomicSingleThread(Dst, LLVMIsAtomicSingleThread(Src));
break;
}
case LLVMStore: {
@@ -656,6 +699,7 @@
LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
+ LLVMSetAtomicSingleThread(Dst, LLVMIsAtomicSingleThread(Src));
break;
}
case LLVMGetElementPtr: {
@@ -726,18 +770,39 @@
}
LLVMAddIncoming(Dst, Values.data(), Blocks.data(), IncomingCount);
+ // Copy fast math flags here since we return early
+ if (LLVMCanValueUseFastMathFlags(Src))
+ LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
return Dst;
}
+ case LLVMSelect: {
+ LLVMValueRef If = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef Then = CloneValue(LLVMGetOperand(Src, 1));
+ LLVMValueRef Else = CloneValue(LLVMGetOperand(Src, 2));
+ Dst = LLVMBuildSelect(Builder, If, Then, Else, Name);
+ break;
+ }
case LLVMCall: {
SmallVector<LLVMValueRef, 8> Args;
- int ArgCount = LLVMGetNumArgOperands(Src);
- for (int i = 0; i < ArgCount; i++)
+ SmallVector<LLVMOperandBundleRef, 8> Bundles;
+ unsigned ArgCount = LLVMGetNumArgOperands(Src);
+ for (unsigned i = 0; i < ArgCount; ++i)
Args.push_back(CloneValue(LLVMGetOperand(Src, i)));
+ unsigned BundleCount = LLVMGetNumOperandBundles(Src);
+ for (unsigned i = 0; i < BundleCount; ++i) {
+ auto Bundle = LLVMGetOperandBundleAtIndex(Src, i);
+ Bundles.push_back(CloneOB(Bundle));
+ LLVMDisposeOperandBundle(Bundle);
+ }
LLVMTypeRef FnTy = CloneType(LLVMGetCalledFunctionType(Src));
LLVMValueRef Fn = CloneValue(LLVMGetCalledValue(Src));
- Dst = LLVMBuildCall2(Builder, FnTy, Fn, Args.data(), ArgCount, Name);
- LLVMSetTailCall(Dst, LLVMIsTailCall(Src));
+ Dst = LLVMBuildCallWithOperandBundles(Builder, FnTy, Fn, Args.data(),
+ ArgCount, Bundles.data(),
+ Bundles.size(), Name);
+ LLVMSetTailCallKind(Dst, LLVMGetTailCallKind(Src));
CloneAttrs(Src, Dst);
+ for (auto Bundle : Bundles)
+ LLVMDisposeOperandBundle(Bundle);
break;
}
case LLVMResume: {
@@ -861,6 +926,62 @@
Dst = LLVMBuildFreeze(Builder, Arg, Name);
break;
}
+ case LLVMFence: {
+ LLVMAtomicOrdering Ordering = LLVMGetOrdering(Src);
+ LLVMBool IsSingleThreaded = LLVMIsAtomicSingleThread(Src);
+ Dst = LLVMBuildFence(Builder, Ordering, IsSingleThreaded, Name);
+ break;
+ }
+ case LLVMZExt: {
+ LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMTypeRef DestTy = CloneType(LLVMTypeOf(Src));
+ LLVMBool NNeg = LLVMGetNNeg(Src);
+ Dst = LLVMBuildZExt(Builder, Val, DestTy, Name);
+ LLVMSetNNeg(Dst, NNeg);
+ break;
+ }
+ case LLVMFAdd: {
+ LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ Dst = LLVMBuildFAdd(Builder, LHS, RHS, Name);
+ break;
+ }
+ case LLVMFSub: {
+ LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ Dst = LLVMBuildFSub(Builder, LHS, RHS, Name);
+ break;
+ }
+ case LLVMFMul: {
+ LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ Dst = LLVMBuildFMul(Builder, LHS, RHS, Name);
+ break;
+ }
+ case LLVMFDiv: {
+ LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ Dst = LLVMBuildFDiv(Builder, LHS, RHS, Name);
+ break;
+ }
+ case LLVMFRem: {
+ LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ Dst = LLVMBuildFRem(Builder, LHS, RHS, Name);
+ break;
+ }
+ case LLVMFNeg: {
+ LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 0));
+ Dst = LLVMBuildFNeg(Builder, Val, Name);
+ break;
+ }
+ case LLVMFCmp: {
+ LLVMRealPredicate Pred = LLVMGetFCmpPredicate(Src);
+ LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+ LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+ Dst = LLVMBuildFCmp(Builder, Pred, LHS, RHS, Name);
+ break;
+ }
default:
break;
}
@@ -870,6 +991,10 @@
exit(-1);
}
+ // Copy fast-math flags on instructions that support them
+ if (LLVMCanValueUseFastMathFlags(Src))
+ LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+
auto Ctx = LLVMGetModuleContext(M);
size_t NumMetadataEntries;
auto *AllMetadata =
@@ -887,6 +1012,17 @@
return VMap[Src] = Dst;
}
+ LLVMOperandBundleRef CloneOB(LLVMOperandBundleRef Src) {
+ size_t TagLen;
+ const char *Tag = LLVMGetOperandBundleTag(Src, &TagLen);
+
+ SmallVector<LLVMValueRef, 8> Args;
+ for (unsigned i = 0, n = LLVMGetNumOperandBundleArgs(Src); i != n; ++i)
+ Args.push_back(CloneValue(LLVMGetOperandBundleArgAtIndex(Src, i)));
+
+ return LLVMCreateOperandBundle(Tag, TagLen, Args.data(), Args.size());
+ }
+
LLVMBasicBlockRef DeclareBB(LLVMBasicBlockRef Src) {
// Check if this is something we already computed.
{
diff --git a/src/llvm-project/llvm/tools/llvm-c-test/main.c b/src/llvm-project/llvm/tools/llvm-c-test/main.c
index 85bbc71..badbe4b 100644
--- a/src/llvm-project/llvm/tools/llvm-c-test/main.c
+++ b/src/llvm-project/llvm/tools/llvm-c-test/main.c
@@ -58,9 +58,6 @@
" Run test for checking if LLVMValueRef is a ValueAsMetadata\n");
fprintf(stderr, " * --echo\n");
fprintf(stderr, " Read bitcode file from stdin - print it back out\n\n");
- fprintf(stderr, " * --echo --opaque-pointers\n");
- fprintf(stderr, " Read bitcode file from stdin - print it back out in "
- "opaque pointer mode\n\n");
fprintf(stderr, " * --test-diagnostic-handler\n");
fprintf(stderr,
" Read bitcode file from stdin with a diagnostic handler set\n\n");
diff --git a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h
index 8fd687d..6b04bc3 100644
--- a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h
+++ b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h
@@ -39,7 +39,6 @@
#include <functional>
#include <set>
#include <string>
-#include <unordered_map>
namespace llvm {
namespace cfi_verify {
diff --git a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h
index 89724c0..55e628a 100644
--- a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h
+++ b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h
@@ -38,8 +38,6 @@
#include <functional>
#include <set>
-#include <string>
-#include <unordered_map>
using Instr = llvm::cfi_verify::FileAnalysis::Instr;
diff --git a/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt
index 35b8b21..e02bda1 100644
--- a/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt
@@ -80,7 +80,7 @@
configure_file(${BUILDVARIABLES_SRCPATH} ${BUILDVARIABLES_OBJPATH} @ONLY)
# Set build-time environment(s).
-add_compile_definitions(CMAKE_CFG_INTDIR="${CMAKE_CFG_INTDIR}")
+add_compile_definitions(CMAKE_CFG_INTDIR="$<CONFIG>")
if(LLVM_ENABLE_MODULES)
target_compile_options(llvm-config PUBLIC
diff --git a/src/llvm-project/llvm/tools/llvm-config/llvm-config.cpp b/src/llvm-project/llvm/tools/llvm-config/llvm-config.cpp
index e86eb2b..d5b76b1 100644
--- a/src/llvm-project/llvm/tools/llvm-config/llvm-config.cpp
+++ b/src/llvm-project/llvm/tools/llvm-config/llvm-config.cpp
@@ -359,18 +359,18 @@
{
SmallString<256> Path(LLVM_INSTALL_INCLUDEDIR);
sys::fs::make_absolute(ActivePrefix, Path);
- ActiveIncludeDir = std::string(Path.str());
+ ActiveIncludeDir = std::string(Path);
}
{
SmallString<256> Path(LLVM_TOOLS_INSTALL_DIR);
sys::fs::make_absolute(ActivePrefix, Path);
- ActiveBinDir = std::string(Path.str());
+ ActiveBinDir = std::string(Path);
}
ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX;
{
SmallString<256> Path(LLVM_INSTALL_PACKAGE_DIR);
sys::fs::make_absolute(ActivePrefix, Path);
- ActiveCMakeDir = std::string(Path.str());
+ ActiveCMakeDir = std::string(Path);
}
ActiveIncludeOption = "-I" + ActiveIncludeDir;
}
@@ -454,11 +454,11 @@
/// extension. Returns true if Lib is in a recognized format.
auto GetComponentLibraryNameSlice = [&](const StringRef &Lib,
StringRef &Out) {
- if (Lib.startswith("lib")) {
+ if (Lib.starts_with("lib")) {
unsigned FromEnd;
- if (Lib.endswith(StaticExt)) {
+ if (Lib.ends_with(StaticExt)) {
FromEnd = StaticExt.size() + 1;
- } else if (Lib.endswith(SharedExt)) {
+ } else if (Lib.ends_with(SharedExt)) {
FromEnd = SharedExt.size() + 1;
} else {
FromEnd = 0;
@@ -481,7 +481,7 @@
// Treat the DyLibName specially. It is not a component library and
// already has the necessary prefix and suffix (e.g. `.so`) added so
// just return it unmodified.
- assert(Lib.endswith(SharedExt) && "DyLib is missing suffix");
+ assert(Lib.ends_with(SharedExt) && "DyLib is missing suffix");
LibFileName = std::string(Lib);
} else {
LibFileName = (SharedPrefix + Lib + "." + SharedExt).str();
@@ -507,7 +507,7 @@
for (int i = 1; i != argc; ++i) {
StringRef Arg = argv[i];
- if (Arg.startswith("-")) {
+ if (Arg.starts_with("-")) {
HasAnyOption = true;
if (Arg == "--version") {
OS << PACKAGE_VERSION << '\n';
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp b/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp
index 02448dc..6405bb1 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -105,6 +105,11 @@
const MemoryBuffer &File,
CoverageData &CoverageInfo);
+ /// Create source views for the MCDC records.
+ void attachMCDCSubViews(SourceCoverageView &View, StringRef SourceName,
+ ArrayRef<MCDCRecord> MCDCRecords,
+ const MemoryBuffer &File, CoverageData &CoverageInfo);
+
/// Create the source view of a particular function.
std::unique_ptr<SourceCoverageView>
createFunctionView(const FunctionRecord &Function,
@@ -162,7 +167,8 @@
/// The coverage data path to be remapped from, and the source path to be
/// remapped to, when using -path-equivalence.
- std::optional<std::pair<std::string, std::string>> PathRemapping;
+ std::optional<std::vector<std::pair<std::string, std::string>>>
+ PathRemappings;
/// File status cache used when finding the same file.
StringMap<std::optional<sys::fs::file_status>> FileStatusCache;
@@ -228,7 +234,7 @@
llvm::sys::fs::file_status Status;
llvm::sys::fs::status(Path, Status);
if (!llvm::sys::fs::exists(Status)) {
- if (PathRemapping)
+ if (PathRemappings)
addCollectedPath(Path);
else
warning("Source file doesn't exist, proceeded by ignoring it.", Path);
@@ -351,6 +357,37 @@
}
}
+void CodeCoverageTool::attachMCDCSubViews(SourceCoverageView &View,
+ StringRef SourceName,
+ ArrayRef<MCDCRecord> MCDCRecords,
+ const MemoryBuffer &File,
+ CoverageData &CoverageInfo) {
+ if (!ViewOpts.ShowMCDC)
+ return;
+
+ const auto *NextRecord = MCDCRecords.begin();
+ const auto *EndRecord = MCDCRecords.end();
+
+ // Group and process MCDC records that have the same line number into the
+ // same subview.
+ while (NextRecord != EndRecord) {
+ std::vector<MCDCRecord> ViewMCDCRecords;
+ unsigned CurrentLine = NextRecord->getDecisionRegion().LineEnd;
+
+ while (NextRecord != EndRecord &&
+ CurrentLine == NextRecord->getDecisionRegion().LineEnd) {
+ ViewMCDCRecords.push_back(*NextRecord++);
+ }
+
+ if (ViewMCDCRecords.empty())
+ continue;
+
+ auto SubView = SourceCoverageView::create(SourceName, File, ViewOpts,
+ std::move(CoverageInfo));
+ View.addMCDCRecord(CurrentLine, ViewMCDCRecords, std::move(SubView));
+ }
+}
+
std::unique_ptr<SourceCoverageView>
CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
const CoverageMapping &Coverage) {
@@ -363,12 +400,15 @@
auto Branches = FunctionCoverage.getBranches();
auto Expansions = FunctionCoverage.getExpansions();
+ auto MCDCRecords = FunctionCoverage.getMCDCRecords();
auto View = SourceCoverageView::create(DC.demangle(Function.Name),
SourceBuffer.get(), ViewOpts,
std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
attachBranchSubViews(*View, DC.demangle(Function.Name), Branches,
SourceBuffer.get(), FunctionCoverage);
+ attachMCDCSubViews(*View, DC.demangle(Function.Name), MCDCRecords,
+ SourceBuffer.get(), FunctionCoverage);
return View;
}
@@ -385,11 +425,14 @@
auto Branches = FileCoverage.getBranches();
auto Expansions = FileCoverage.getExpansions();
+ auto MCDCRecords = FileCoverage.getMCDCRecords();
auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
ViewOpts, std::move(FileCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
attachBranchSubViews(*View, SourceFile, Branches, SourceBuffer.get(),
FileCoverage);
+ attachMCDCSubViews(*View, SourceFile, MCDCRecords, SourceBuffer.get(),
+ FileCoverage);
if (!ViewOpts.ShowFunctionInstantiations)
return View;
@@ -407,11 +450,14 @@
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
auto SubViewExpansions = SubViewCoverage.getExpansions();
auto SubViewBranches = SubViewCoverage.getBranches();
+ auto SubViewMCDCRecords = SubViewCoverage.getMCDCRecords();
SubView = SourceCoverageView::create(
Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
attachBranchSubViews(*SubView, SourceFile, SubViewBranches,
SourceBuffer.get(), SubViewCoverage);
+ attachMCDCSubViews(*SubView, SourceFile, SubViewMCDCRecords,
+ SourceBuffer.get(), SubViewCoverage);
}
unsigned FileID = Function->CountedRegions.front().FileID;
@@ -446,7 +492,7 @@
ObjectFilenames, PGOFilename, *FS, CoverageArches,
ViewOpts.CompilationDirectory, BIDFetcher.get(), CheckBinaryIDs);
if (Error E = CoverageOrErr.takeError()) {
- error("Failed to load coverage: " + toString(std::move(E)));
+ error("failed to load coverage: " + toString(std::move(E)));
return nullptr;
}
auto Coverage = std::move(CoverageOrErr.get());
@@ -474,7 +520,7 @@
}
void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
- if (!PathRemapping)
+ if (!PathRemappings)
return;
// Convert remapping paths to native paths with trailing seperators.
@@ -488,17 +534,23 @@
NativePath += sys::path::get_separator();
return NativePath.c_str();
};
- std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
- std::string RemapTo = nativeWithTrailing(PathRemapping->second);
- // Create a mapping from coverage data file paths to local paths.
- for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
- SmallString<128> NativeFilename;
- sys::path::native(Filename, NativeFilename);
- sys::path::remove_dots(NativeFilename, true);
- if (NativeFilename.startswith(RemapFrom)) {
- RemappedFilenames[Filename] =
- RemapTo + NativeFilename.substr(RemapFrom.size()).str();
+ for (std::pair<std::string, std::string> &PathRemapping : *PathRemappings) {
+ std::string RemapFrom = nativeWithTrailing(PathRemapping.first);
+ std::string RemapTo = nativeWithTrailing(PathRemapping.second);
+
+ // Create a mapping from coverage data file paths to local paths.
+ for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
+ if (RemappedFilenames.count(Filename) == 1)
+ continue;
+
+ SmallString<128> NativeFilename;
+ sys::path::native(Filename, NativeFilename);
+ sys::path::remove_dots(NativeFilename, true);
+ if (NativeFilename.starts_with(RemapFrom)) {
+ RemappedFilenames[Filename] =
+ RemapTo + NativeFilename.substr(RemapFrom.size()).str();
+ }
}
}
@@ -592,7 +644,7 @@
DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
/*KeepEmpty=*/false);
if (Symbols.size() != NumSymbols) {
- error("Demangler did not provide expected number of symbols");
+ error("demangler did not provide expected number of symbols");
return;
}
@@ -616,7 +668,7 @@
auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
if (Error E = OSOrErr.takeError()) {
- error("Could not create view file!", toString(std::move(E)));
+ error("could not create view file!", toString(std::move(E)));
return;
}
auto OS = std::move(OSOrErr.get());
@@ -674,7 +726,7 @@
"lcov tracefile output")),
cl::init(CoverageViewOptions::OutputFormat::Text));
- cl::opt<std::string> PathRemap(
+ cl::list<std::string> PathRemaps(
"path-equivalence", cl::Optional,
cl::desc("<from>,<to> Map coverage data paths to local source file "
"paths"));
@@ -745,6 +797,10 @@
cl::desc("Show branch condition statistics in summary table"),
cl::init(true));
+ cl::opt<bool> MCDCSummary("show-mcdc-summary", cl::Optional,
+ cl::desc("Show MCDC statistics in summary table"),
+ cl::init(false));
+
cl::opt<bool> InstantiationSummary(
"show-instantiation-summary", cl::Optional,
cl::desc("Show instantiation statistics in summary table"));
@@ -812,26 +868,30 @@
break;
}
- // If path-equivalence was given and is a comma seperated pair then set
- // PathRemapping.
- if (!PathRemap.empty()) {
- auto EquivPair = StringRef(PathRemap).split(',');
- if (EquivPair.first.empty() || EquivPair.second.empty()) {
- error("invalid argument '" + PathRemap +
- "', must be in format 'from,to'",
- "-path-equivalence");
- return 1;
+ if (!PathRemaps.empty()) {
+ std::vector<std::pair<std::string, std::string>> Remappings;
+
+ for (const std::string &PathRemap : PathRemaps) {
+ auto EquivPair = StringRef(PathRemap).split(',');
+ if (EquivPair.first.empty() || EquivPair.second.empty()) {
+ error("invalid argument '" + PathRemap +
+ "', must be in format 'from,to'",
+ "-path-equivalence");
+ return 1;
+ }
+
+ Remappings.push_back(
+ {std::string(EquivPair.first), std::string(EquivPair.second)});
}
- PathRemapping = {std::string(EquivPair.first),
- std::string(EquivPair.second)};
+ PathRemappings = Remappings;
}
// If a demangler is supplied, check if it exists and register it.
if (!DemanglerOpts.empty()) {
auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
if (!DemanglerPathOrErr) {
- error("Could not find the demangler!",
+ error("could not find the demangler!",
DemanglerPathOrErr.getError().message());
return 1;
}
@@ -890,14 +950,14 @@
if (!Arches.empty()) {
for (const std::string &Arch : Arches) {
if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
- error("Unknown architecture: " + Arch);
+ error("unknown architecture: " + Arch);
return 1;
}
CoverageArches.emplace_back(Arch);
}
if (CoverageArches.size() != 1 &&
CoverageArches.size() != ObjectFilenames.size()) {
- error("Number of architectures doesn't match the number of objects");
+ error("number of architectures doesn't match the number of objects");
return 1;
}
}
@@ -912,6 +972,7 @@
::exit(0);
}
+ ViewOpts.ShowMCDCSummary = MCDCSummary;
ViewOpts.ShowBranchSummary = BranchSummary;
ViewOpts.ShowRegionSummary = RegionSummary;
ViewOpts.ShowInstantiationSummary = InstantiationSummary;
@@ -957,6 +1018,11 @@
"percent", "Show True/False percent")),
cl::init(CoverageViewOptions::BranchOutputType::Off));
+ cl::opt<bool> ShowMCDC(
+ "show-mcdc", cl::Optional,
+ cl::desc("Show the MCDC Coverage for each applicable boolean expression"),
+ cl::cat(ViewCategory));
+
cl::opt<bool> ShowBestLineRegionsCounts(
"show-line-counts-or-regions", cl::Optional,
cl::desc("Show the execution counts for each line, or the execution "
@@ -971,6 +1037,10 @@
cl::desc("Show function instantiations"),
cl::init(true), cl::cat(ViewCategory));
+ cl::opt<bool> ShowDirectoryCoverage("show-directory-coverage", cl::Optional,
+ cl::desc("Show directory coverage"),
+ cl::cat(ViewCategory));
+
cl::opt<std::string> ShowOutputDirectory(
"output-dir", cl::init(""),
cl::desc("Directory in which coverage information is written out"));
@@ -996,7 +1066,7 @@
return Err;
if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
- error("Lcov format should be used with 'llvm-cov export'.");
+ error("lcov format should be used with 'llvm-cov export'.");
return 1;
}
@@ -1048,23 +1118,25 @@
ViewOpts.ShowExpandedRegions = ShowExpansions;
ViewOpts.ShowBranchCounts =
ShowBranches == CoverageViewOptions::BranchOutputType::Count;
+ ViewOpts.ShowMCDC = ShowMCDC;
ViewOpts.ShowBranchPercents =
ShowBranches == CoverageViewOptions::BranchOutputType::Percent;
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
+ ViewOpts.ShowDirectoryCoverage = ShowDirectoryCoverage;
ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
ViewOpts.TabSize = TabSize;
ViewOpts.ProjectTitle = ProjectTitle;
if (ViewOpts.hasOutputDirectory()) {
if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
- error("Could not create output directory!", E.message());
+ error("could not create output directory!", E.message());
return 1;
}
}
sys::fs::file_status Status;
if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("Could not read profile data!" + EC.message(), PGOFilename);
+ error("could not read profile data!" + EC.message(), PGOFilename);
return 1;
}
@@ -1091,7 +1163,7 @@
// Create an index out of the source files.
if (ViewOpts.hasOutputDirectory()) {
if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
- error("Could not create index file!", toString(std::move(E)));
+ error("could not create index file!", toString(std::move(E)));
return 1;
}
}
@@ -1112,7 +1184,7 @@
auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
if (Error E = OSOrErr.takeError()) {
- error("Could not create view file!", toString(std::move(E)));
+ error("could not create view file!", toString(std::move(E)));
return 1;
}
auto OS = std::move(OSOrErr.get());
@@ -1177,13 +1249,13 @@
error("HTML output for summary reports is not yet supported.");
return 1;
} else if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
- error("Lcov format should be used with 'llvm-cov export'.");
+ error("lcov format should be used with 'llvm-cov export'.");
return 1;
}
sys::fs::file_status Status;
if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("Could not read profile data!" + EC.message(), PGOFilename);
+ error("could not read profile data!" + EC.message(), PGOFilename);
return 1;
}
@@ -1199,7 +1271,7 @@
Report.renderFileReports(llvm::outs(), SourceFiles);
} else {
if (SourceFiles.empty()) {
- error("Source files must be specified when -show-functions=true is "
+ error("source files must be specified when -show-functions=true is "
"specified");
return 1;
}
@@ -1236,20 +1308,20 @@
if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
- error("Coverage data can only be exported as textual JSON or an "
+ error("coverage data can only be exported as textual JSON or an "
"lcov tracefile.");
return 1;
}
sys::fs::file_status Status;
if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("Could not read profile data!" + EC.message(), PGOFilename);
+ error("could not read profile data!" + EC.message(), PGOFilename);
return 1;
}
auto Coverage = load();
if (!Coverage) {
- error("Could not load coverage information");
+ error("could not load coverage information");
return 1;
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 9e43377..a424bbe 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -20,6 +20,8 @@
// -- File: dict => Coverage for a single file
// -- Branches: array => List of Branches in the file
// -- Branch: dict => Describes a branch of the file with counters
+// -- MCDC Records: array => List of MCDC records in the file
+// -- MCDC Values: array => List of T/F covered condition values
// -- Segments: array => List of Segments contained in the file
// -- Segment: dict => Describes a segment of the file with a counter
// -- Expansions: array => List of expansion records
@@ -34,6 +36,7 @@
// -- FunctionCoverage: dict => Object summarizing function coverage
// -- RegionCoverage: dict => Object summarizing region coverage
// -- BranchCoverage: dict => Object summarizing branch coverage
+// -- MCDCCoverage: dict => Object summarizing MC/DC coverage
// -- Functions: array => List of objects describing coverage for functions
// -- Function: dict => Coverage info for a single function
// -- Filenames: array => List of filenames that the function relates to
@@ -43,6 +46,7 @@
// -- InstantiationCoverage: dict => Object summarizing inst. coverage
// -- RegionCoverage: dict => Object summarizing region coverage
// -- BranchCoverage: dict => Object summarizing branch coverage
+// -- MCDCCoverage: dict => Object summarizing MC/DC coverage
//
//===----------------------------------------------------------------------===//
@@ -97,6 +101,20 @@
Region.ExpandedFileID, int64_t(Region.Kind)});
}
+json::Array gatherConditions(const coverage::MCDCRecord &Record) {
+ json::Array Conditions;
+ for (unsigned c = 0; c < Record.getNumConditions(); c++)
+ Conditions.push_back(Record.isConditionIndependencePairCovered(c));
+ return Conditions;
+}
+
+json::Array renderMCDCRecord(const coverage::MCDCRecord &Record) {
+ const llvm::coverage::CounterMappingRegion &CMR = Record.getDecisionRegion();
+ return json::Array({CMR.LineStart, CMR.ColumnStart, CMR.LineEnd,
+ CMR.ColumnEnd, CMR.ExpandedFileID, int64_t(CMR.Kind),
+ gatherConditions(Record)});
+}
+
json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
json::Array RegionArray;
for (const auto &Region : Regions)
@@ -112,6 +130,13 @@
return RegionArray;
}
+json::Array renderMCDCRecords(ArrayRef<coverage::MCDCRecord> Records) {
+ json::Array RecordArray;
+ for (auto &Record : Records)
+ RecordArray.push_back(renderMCDCRecord(Record));
+ return RecordArray;
+}
+
std::vector<llvm::coverage::CountedRegion>
collectNestedBranches(const coverage::CoverageMapping &Coverage,
ArrayRef<llvm::coverage::ExpansionRecord> Expansions) {
@@ -178,7 +203,14 @@
{"covered", int64_t(Summary.BranchCoverage.getCovered())},
{"notcovered", int64_t(Summary.BranchCoverage.getNumBranches() -
Summary.BranchCoverage.getCovered())},
- {"percent", Summary.BranchCoverage.getPercentCovered()}})}});
+ {"percent", Summary.BranchCoverage.getPercentCovered()}})},
+ {"mcdc",
+ json::Object(
+ {{"count", int64_t(Summary.MCDCCoverage.getNumPairs())},
+ {"covered", int64_t(Summary.MCDCCoverage.getCoveredPairs())},
+ {"notcovered", int64_t(Summary.MCDCCoverage.getNumPairs() -
+ Summary.MCDCCoverage.getCoveredPairs())},
+ {"percent", Summary.MCDCCoverage.getPercentCovered()}})}});
}
json::Array renderFileExpansions(const coverage::CoverageMapping &Coverage,
@@ -206,6 +238,14 @@
return BranchArray;
}
+json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage,
+ const FileCoverageSummary &FileReport) {
+ json::Array MCDCRecordArray;
+ for (const auto &Record : FileCoverage.getMCDCRecords())
+ MCDCRecordArray.push_back(renderMCDCRecord(Record));
+ return MCDCRecordArray;
+}
+
json::Object renderFile(const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport,
@@ -216,6 +256,7 @@
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
File["branches"] = renderFileBranches(FileCoverage, FileReport);
+ File["mcdc_records"] = renderFileMCDC(FileCoverage, FileReport);
if (!Options.SkipExpansions) {
File["expansions"] =
renderFileExpansions(Coverage, FileCoverage, FileReport);
@@ -264,6 +305,7 @@
{"count", clamp_uint64_to_int64(F.ExecutionCount)},
{"regions", renderRegions(F.CountedRegions)},
{"branches", renderBranchRegions(F.CountedBranchRegions)},
+ {"mcdc_records", renderMCDCRecords(F.MCDCRecords)},
{"filenames", json::Array(F.Filenames)}}));
return FunctionArray;
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp
index cb0b184..8cc073e 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -12,7 +12,6 @@
#include "CoverageReport.h"
#include "RenderingSupport.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
@@ -87,9 +86,9 @@
}
// Specify the default column widths.
-size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10, 16,
- 16, 10, 12, 18, 10, 12, 18, 10};
-size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8, 10, 8, 8};
+size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10, 16, 16, 10,
+ 12, 18, 10, 12, 18, 10, 20, 21, 10};
+size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8, 10, 8, 8, 20, 8, 8};
/// Adjust column widths to fit long file paths and function names.
void adjustColumnWidths(ArrayRef<StringRef> Files,
@@ -166,6 +165,35 @@
return PrefixLen;
}
+/// Determine the length of the longest redundant prefix of the substrs starts
+/// from \p LCP in \p Paths. \p Paths can't be empty. If there's only one
+/// element in \p Paths, the length of the substr is returned. Note this is
+/// differnet from the behavior of the function above.
+unsigned getRedundantPrefixLen(ArrayRef<StringRef> Paths, unsigned LCP) {
+ assert(!Paths.empty() && "Paths must have at least one element");
+
+ auto Iter = Paths.begin();
+ auto IterE = Paths.end();
+ auto Prefix = Iter->substr(LCP);
+ while (++Iter != IterE) {
+ auto Other = Iter->substr(LCP);
+ auto Len = std::min(Prefix.size(), Other.size());
+ for (std::size_t I = 0; I < Len; ++I) {
+ if (Prefix[I] != Other[I]) {
+ Prefix = Prefix.substr(0, I);
+ break;
+ }
+ }
+ }
+
+ for (auto I = Prefix.size(); --I != SIZE_MAX;) {
+ if (Prefix[I] == '/' || Prefix[I] == '\\')
+ return I + 1;
+ }
+
+ return Prefix.size();
+}
+
} // end anonymous namespace
namespace llvm {
@@ -180,8 +208,14 @@
determineCoveragePercentageColor(File.InstantiationCoverage);
auto LineCoverageColor = determineCoveragePercentageColor(File.LineCoverage);
SmallString<256> FileName = File.Name;
- sys::path::remove_dots(FileName, /*remove_dot_dot=*/true);
sys::path::native(FileName);
+
+ // remove_dots will remove trailing slash, so we need to check before it.
+ auto IsDir = FileName.ends_with(sys::path::get_separator());
+ sys::path::remove_dots(FileName, /*remove_dot_dot=*/true);
+ if (IsDir)
+ FileName += sys::path::get_separator();
+
OS << column(FileName, FileReportColumns[0], Column::NoTrim);
if (Options.ShowRegionSummary) {
@@ -257,6 +291,22 @@
OS << column("-", FileReportColumns[15], Column::RightAlignment);
}
+ if (Options.ShowMCDCSummary) {
+ OS << format("%*u", FileReportColumns[16],
+ (unsigned)File.MCDCCoverage.getNumPairs());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FileReportColumns[17],
+ (unsigned)(File.MCDCCoverage.getNumPairs() -
+ File.MCDCCoverage.getCoveredPairs()));
+ if (File.MCDCCoverage.getNumPairs())
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*.2f", FileReportColumns[18] - 1,
+ File.MCDCCoverage.getPercentCovered())
+ << '%';
+ else
+ OS << column("-", FileReportColumns[18], Column::RightAlignment);
+ }
+
OS << "\n";
}
@@ -304,6 +354,19 @@
Function.BranchCoverage.getPercentCovered())
<< '%';
}
+ if (Options.ShowMCDCSummary) {
+ OS << format("%*u", FunctionReportColumns[10],
+ (unsigned)Function.MCDCCoverage.getNumPairs());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FunctionReportColumns[11],
+ (unsigned)(Function.MCDCCoverage.getNumPairs() -
+ Function.MCDCCoverage.getCoveredPairs()));
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(Function.MCDCCoverage))
+ << format("%*.2f", FunctionReportColumns[12] - 1,
+ Function.MCDCCoverage.getPercentCovered())
+ << '%';
+ }
OS << "\n";
}
@@ -336,6 +399,11 @@
OS << column("Branches", FunctionReportColumns[7], Column::RightAlignment)
<< column("Miss", FunctionReportColumns[8], Column::RightAlignment)
<< column("Cover", FunctionReportColumns[9], Column::RightAlignment);
+ if (Options.ShowMCDCSummary)
+ OS << column("MC/DC Conditions", FunctionReportColumns[10],
+ Column::RightAlignment)
+ << column("Miss", FunctionReportColumns[11], Column::RightAlignment)
+ << column("Cover", FunctionReportColumns[12], Column::RightAlignment);
OS << "\n";
renderDivider(FunctionReportColumns, OS);
OS << "\n";
@@ -346,6 +414,7 @@
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
Totals.BranchCoverage += Function.BranchCoverage;
+ Totals.MCDCCoverage += Function.MCDCCoverage;
render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
@@ -436,7 +505,12 @@
FileCoverageSummary Totals("TOTAL");
auto FileReports =
prepareFileReports(Coverage, Totals, Files, Options, Filters);
+ renderFileReports(OS, FileReports, Totals, Filters.empty());
+}
+void CoverageReport::renderFileReports(
+ raw_ostream &OS, const std::vector<FileCoverageSummary> &FileReports,
+ const FileCoverageSummary &Totals, bool ShowEmptyFiles) const {
std::vector<StringRef> Filenames;
Filenames.reserve(FileReports.size());
for (const FileCoverageSummary &FCS : FileReports)
@@ -463,25 +537,30 @@
<< column("Missed Branches", FileReportColumns[14],
Column::RightAlignment)
<< column("Cover", FileReportColumns[15], Column::RightAlignment);
+ if (Options.ShowMCDCSummary)
+ OS << column("MC/DC Conditions", FileReportColumns[16],
+ Column::RightAlignment)
+ << column("Missed Conditions", FileReportColumns[17],
+ Column::RightAlignment)
+ << column("Cover", FileReportColumns[18], Column::RightAlignment);
OS << "\n";
renderDivider(FileReportColumns, OS);
OS << "\n";
- bool EmptyFiles = false;
+ std::vector<const FileCoverageSummary *> EmptyFiles;
for (const FileCoverageSummary &FCS : FileReports) {
if (FCS.FunctionCoverage.getNumFunctions())
render(FCS, OS);
else
- EmptyFiles = true;
+ EmptyFiles.push_back(&FCS);
}
- if (EmptyFiles && Filters.empty()) {
+ if (!EmptyFiles.empty() && ShowEmptyFiles) {
OS << "\n"
<< "Files which contain no functions:\n";
- for (const FileCoverageSummary &FCS : FileReports)
- if (!FCS.FunctionCoverage.getNumFunctions())
- render(FCS, OS);
+ for (auto FCS : EmptyFiles)
+ render(*FCS, OS);
}
renderDivider(FileReportColumns, OS);
@@ -489,4 +568,96 @@
render(Totals, OS);
}
+Expected<FileCoverageSummary> DirectoryCoverageReport::prepareDirectoryReports(
+ ArrayRef<std::string> SourceFiles) {
+ std::vector<StringRef> Files(SourceFiles.begin(), SourceFiles.end());
+
+ unsigned RootLCP = getRedundantPrefixLen(Files, 0);
+ auto LCPath = Files.front().substr(0, RootLCP);
+
+ ThreadPoolStrategy PoolS = hardware_concurrency(Options.NumThreads);
+ if (Options.NumThreads == 0) {
+ PoolS = heavyweight_hardware_concurrency(Files.size());
+ PoolS.Limit = true;
+ }
+ ThreadPool Pool(PoolS);
+
+ TPool = &Pool;
+ LCPStack = {RootLCP};
+ FileCoverageSummary RootTotals(LCPath);
+ if (auto E = prepareSubDirectoryReports(Files, &RootTotals))
+ return {std::move(E)};
+ return {std::move(RootTotals)};
+}
+
+/// Filter out files in LCPStack.back(), group others by subdirectory name
+/// and recurse on them. After returning from all subdirectories, call
+/// generateSubDirectoryReport(). \p Files must be non-empty. The
+/// FileCoverageSummary of this directory will be added to \p Totals.
+Error DirectoryCoverageReport::prepareSubDirectoryReports(
+ const ArrayRef<StringRef> &Files, FileCoverageSummary *Totals) {
+ assert(!Files.empty() && "Files must have at least one element");
+
+ auto LCP = LCPStack.back();
+ auto LCPath = Files.front().substr(0, LCP).str();
+
+ // Use ordered map to keep entries in order.
+ SubFileReports SubFiles;
+ SubDirReports SubDirs;
+ for (auto &&File : Files) {
+ auto SubPath = File.substr(LCPath.size());
+ SmallVector<char, 128> NativeSubPath;
+ sys::path::native(SubPath, NativeSubPath);
+ StringRef NativeSubPathRef(NativeSubPath.data(), NativeSubPath.size());
+
+ auto I = sys::path::begin(NativeSubPathRef);
+ auto E = sys::path::end(NativeSubPathRef);
+ assert(I != E && "Such case should have been filtered out in the caller");
+
+ auto Name = SubPath.substr(0, I->size());
+ if (++I == E) {
+ auto Iter = SubFiles.insert_or_assign(Name, SubPath).first;
+ // Makes files reporting overlap with subdir reporting.
+ TPool->async(&CoverageReport::prepareSingleFileReport, File, &Coverage,
+ Options, LCP, &Iter->second, &Filters);
+ } else {
+ SubDirs[Name].second.push_back(File);
+ }
+ }
+
+ // Call recursively on subdirectories.
+ for (auto &&KV : SubDirs) {
+ auto &V = KV.second;
+ if (V.second.size() == 1) {
+ // If there's only one file in that subdirectory, we don't bother to
+ // recurse on it further.
+ V.first.Name = V.second.front().substr(LCP);
+ TPool->async(&CoverageReport::prepareSingleFileReport, V.second.front(),
+ &Coverage, Options, LCP, &V.first, &Filters);
+ } else {
+ auto SubDirLCP = getRedundantPrefixLen(V.second, LCP);
+ V.first.Name = V.second.front().substr(LCP, SubDirLCP);
+ LCPStack.push_back(LCP + SubDirLCP);
+ if (auto E = prepareSubDirectoryReports(V.second, &V.first))
+ return E;
+ }
+ }
+
+ TPool->wait();
+
+ FileCoverageSummary CurrentTotals(LCPath);
+ for (auto &&KV : SubFiles)
+ CurrentTotals += KV.second;
+ for (auto &&KV : SubDirs)
+ CurrentTotals += KV.second.first;
+ *Totals += CurrentTotals;
+
+ if (auto E = generateSubDirectoryReport(
+ std::move(SubFiles), std::move(SubDirs), std::move(CurrentTotals)))
+ return E;
+
+ LCPStack.pop_back();
+ return Error::success();
+}
+
} // end namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.h b/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.h
index f9a092f..60f751c 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.h
@@ -16,9 +16,12 @@
#include "CoverageFilters.h"
#include "CoverageSummaryInfo.h"
#include "CoverageViewOptions.h"
+#include <map>
namespace llvm {
+class ThreadPool;
+
/// Displays the code coverage report.
class CoverageReport {
const CoverageViewOptions &Options;
@@ -62,6 +65,73 @@
/// in \p Filters.
void renderFileReports(raw_ostream &OS, ArrayRef<std::string> Files,
const CoverageFiltersMatchAll &Filters) const;
+
+ /// Render file reports with given data.
+ void renderFileReports(raw_ostream &OS,
+ const std::vector<FileCoverageSummary> &FileReports,
+ const FileCoverageSummary &Totals,
+ bool ShowEmptyFiles) const;
+};
+
+/// Prepare reports for every non-trivial directories (which have more than 1
+/// source files) of the source files. This class uses template method pattern.
+class DirectoryCoverageReport {
+public:
+ DirectoryCoverageReport(
+ const CoverageViewOptions &Options,
+ const coverage::CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters = CoverageFiltersMatchAll())
+ : Options(Options), Coverage(Coverage), Filters(Filters) {}
+
+ virtual ~DirectoryCoverageReport() = default;
+
+ /// Prepare file reports for each directory in \p SourceFiles. The total
+ /// report for all files is returned and its Name is set to the LCP of all
+ /// files. The size of \p SourceFiles must be greater than 1 or else the
+ /// behavior is undefined, in which case you should use
+ /// CoverageReport::prepareSingleFileReport instead. If an error occurs,
+ /// the recursion will stop immediately.
+ Expected<FileCoverageSummary>
+ prepareDirectoryReports(ArrayRef<std::string> SourceFiles);
+
+protected:
+ // These member variables below are used for avoiding being passed
+ // repeatedly in recursion.
+ const CoverageViewOptions &Options;
+ const coverage::CoverageMapping &Coverage;
+ const CoverageFiltersMatchAll &Filters;
+
+ /// For calling CoverageReport::prepareSingleFileReport asynchronously
+ /// in prepareSubDirectoryReports(). It's not intended to be modified by
+ /// generateSubDirectoryReport().
+ ThreadPool *TPool;
+
+ /// One report level may correspond to multiple directory levels as we omit
+ /// directories which have only one subentry. So we use this Stack to track
+ /// each report level's corresponding drectory level.
+ /// Each value in the stack is the LCP prefix length length of that report
+ /// level. LCPStack.front() is the root LCP. Current LCP is LCPStack.back().
+ SmallVector<unsigned, 32> LCPStack;
+
+ // Use std::map to sort table rows in order.
+ using SubFileReports = std::map<StringRef, FileCoverageSummary>;
+ using SubDirReports =
+ std::map<StringRef,
+ std::pair<FileCoverageSummary, SmallVector<StringRef, 0>>>;
+
+ /// This method is called when a report level is prepared during the
+ /// recursion. \p SubFiles are the reports for those files directly in the
+ /// current directory. \p SubDirs are the reports for subdirectories in
+ /// current directory. \p SubTotals is the sum of all, and its name is the
+ /// current LCP. Note that this method won't be called for trivial
+ /// directories.
+ virtual Error generateSubDirectoryReport(SubFileReports &&SubFiles,
+ SubDirReports &&SubDirs,
+ FileCoverageSummary &&SubTotals) = 0;
+
+private:
+ Error prepareSubDirectoryReports(const ArrayRef<StringRef> &Files,
+ FileCoverageSummary *Totals);
};
} // end namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 10e059a..4f15002 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -44,6 +44,21 @@
}
}
+static std::pair<size_t, size_t>
+sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
+ size_t NumPairs = 0, CoveredPairs = 0;
+ for (const auto &Record : Records) {
+ const auto NumConditions = Record.getNumConditions();
+ for (unsigned C = 0; C < NumConditions; C++) {
+ if (!Record.isCondFolded(C))
+ ++NumPairs;
+ if (Record.isConditionIndependencePairCovered(C))
+ ++CoveredPairs;
+ }
+ }
+ return {NumPairs, CoveredPairs};
+}
+
FunctionCoverageSummary
FunctionCoverageSummary::get(const CoverageMapping &CM,
const coverage::FunctionRecord &Function) {
@@ -73,11 +88,15 @@
sumBranches(NumBranches, CoveredBranches, CD.getBranches());
sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
+ size_t NumPairs = 0, CoveredPairs = 0;
+ std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords());
+
return FunctionCoverageSummary(
Function.Name, Function.ExecutionCount,
RegionCoverageInfo(CoveredRegions, NumCodeRegions),
LineCoverageInfo(CoveredLines, NumLines),
- BranchCoverageInfo(CoveredBranches, NumBranches));
+ BranchCoverageInfo(CoveredBranches, NumBranches),
+ MCDCCoverageInfo(CoveredPairs, NumPairs));
}
FunctionCoverageSummary
@@ -97,10 +116,12 @@
Summary.RegionCoverage = Summaries[0].RegionCoverage;
Summary.LineCoverage = Summaries[0].LineCoverage;
Summary.BranchCoverage = Summaries[0].BranchCoverage;
+ Summary.MCDCCoverage = Summaries[0].MCDCCoverage;
for (const auto &FCS : Summaries.drop_front()) {
Summary.RegionCoverage.merge(FCS.RegionCoverage);
Summary.LineCoverage.merge(FCS.LineCoverage);
Summary.BranchCoverage.merge(FCS.BranchCoverage);
+ Summary.MCDCCoverage.merge(FCS.MCDCCoverage);
}
return Summary;
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 84a3228..64c2c84 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -142,6 +142,47 @@
}
};
+/// Provides information about MC/DC coverage for a function/file.
+class MCDCCoverageInfo {
+ /// The number of Independence Pairs that were covered.
+ size_t CoveredPairs;
+
+ /// The total number of Independence Pairs in a function/file.
+ size_t NumPairs;
+
+public:
+ MCDCCoverageInfo() : CoveredPairs(0), NumPairs(0) {}
+
+ MCDCCoverageInfo(size_t CoveredPairs, size_t NumPairs)
+ : CoveredPairs(CoveredPairs), NumPairs(NumPairs) {
+ assert(CoveredPairs <= NumPairs && "Covered pairs over-counted");
+ }
+
+ MCDCCoverageInfo &operator+=(const MCDCCoverageInfo &RHS) {
+ CoveredPairs += RHS.CoveredPairs;
+ NumPairs += RHS.NumPairs;
+ return *this;
+ }
+
+ void merge(const MCDCCoverageInfo &RHS) {
+ CoveredPairs = std::max(CoveredPairs, RHS.CoveredPairs);
+ NumPairs = std::max(NumPairs, RHS.NumPairs);
+ }
+
+ size_t getCoveredPairs() const { return CoveredPairs; }
+
+ size_t getNumPairs() const { return NumPairs; }
+
+ bool isFullyCovered() const { return CoveredPairs == NumPairs; }
+
+ double getPercentCovered() const {
+ assert(CoveredPairs <= NumPairs && "Covered pairs over-counted");
+ if (NumPairs == 0)
+ return 0.0;
+ return double(CoveredPairs) / double(NumPairs) * 100.0;
+ }
+};
+
/// Provides information about function coverage for a file.
class FunctionCoverageInfo {
/// The number of functions that were executed.
@@ -189,6 +230,7 @@
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
BranchCoverageInfo BranchCoverage;
+ MCDCCoverageInfo MCDCCoverage;
FunctionCoverageSummary(const std::string &Name)
: Name(Name), ExecutionCount(0) {}
@@ -196,10 +238,11 @@
FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount,
const RegionCoverageInfo &RegionCoverage,
const LineCoverageInfo &LineCoverage,
- const BranchCoverageInfo &BranchCoverage)
+ const BranchCoverageInfo &BranchCoverage,
+ const MCDCCoverageInfo &MCDCCoverage)
: Name(Name), ExecutionCount(ExecutionCount),
RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
- BranchCoverage(BranchCoverage) {}
+ BranchCoverage(BranchCoverage), MCDCCoverage(MCDCCoverage) {}
/// Compute the code coverage summary for the given function coverage
/// mapping record.
@@ -219,9 +262,11 @@
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
BranchCoverageInfo BranchCoverage;
+ MCDCCoverageInfo MCDCCoverage;
FunctionCoverageInfo FunctionCoverage;
FunctionCoverageInfo InstantiationCoverage;
+ FileCoverageSummary() = default;
FileCoverageSummary(StringRef Name) : Name(Name) {}
FileCoverageSummary &operator+=(const FileCoverageSummary &RHS) {
@@ -229,6 +274,7 @@
LineCoverage += RHS.LineCoverage;
FunctionCoverage += RHS.FunctionCoverage;
BranchCoverage += RHS.BranchCoverage;
+ MCDCCoverage += RHS.MCDCCoverage;
InstantiationCoverage += RHS.InstantiationCoverage;
return *this;
}
@@ -237,6 +283,7 @@
RegionCoverage += Function.RegionCoverage;
LineCoverage += Function.LineCoverage;
BranchCoverage += Function.BranchCoverage;
+ MCDCCoverage += Function.MCDCCoverage;
FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h b/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h
index fedf2df..6925cff 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -30,14 +30,17 @@
bool ShowLineNumbers;
bool ShowLineStats;
bool ShowRegionMarkers;
+ bool ShowMCDC;
bool ShowBranchCounts;
bool ShowBranchPercents;
bool ShowExpandedRegions;
bool ShowFunctionInstantiations;
bool ShowFullFilenames;
bool ShowBranchSummary;
+ bool ShowMCDCSummary;
bool ShowRegionSummary;
bool ShowInstantiationSummary;
+ bool ShowDirectoryCoverage;
bool ExportSummaryOnly;
bool SkipExpansions;
bool SkipFunctions;
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp
index ea86aca..5b85d7d 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -48,7 +48,7 @@
sys::path::append(FullPath, PathFilename);
sys::path::native(FullPath);
- return std::string(FullPath.str());
+ return std::string(FullPath);
}
Expected<CoveragePrinter::OwnedStream>
@@ -76,8 +76,12 @@
CoveragePrinter::create(const CoverageViewOptions &Opts) {
switch (Opts.Format) {
case CoverageViewOptions::OutputFormat::Text:
+ if (Opts.ShowDirectoryCoverage)
+ return std::make_unique<CoveragePrinterTextDirectory>(Opts);
return std::make_unique<CoveragePrinterText>(Opts);
case CoverageViewOptions::OutputFormat::HTML:
+ if (Opts.ShowDirectoryCoverage)
+ return std::make_unique<CoveragePrinterHTMLDirectory>(Opts);
return std::make_unique<CoveragePrinterHTML>(Opts);
case CoverageViewOptions::OutputFormat::Lcov:
// Unreachable because CodeCoverage.cpp should terminate with an error
@@ -126,6 +130,8 @@
const auto *CurSeg = Segments[I];
if (!CurSeg->IsRegionEntry || CurSeg->Count == LCS.getExecutionCount())
continue;
+ if (!CurSeg->HasCount) // don't show tooltips for SkippedRegions
+ continue;
return true;
}
return false;
@@ -133,7 +139,7 @@
bool SourceCoverageView::hasSubViews() const {
return !ExpansionSubViews.empty() || !InstantiationSubViews.empty() ||
- !BranchSubViews.empty();
+ !BranchSubViews.empty() || !MCDCSubViews.empty();
}
std::unique_ptr<SourceCoverageView>
@@ -159,7 +165,7 @@
SmallString<128> SourceText(SourceName);
sys::path::remove_dots(SourceText, /*remove_dot_dot=*/true);
sys::path::native(SourceText);
- return std::string(SourceText.str());
+ return std::string(SourceText);
}
void SourceCoverageView::addExpansion(
@@ -174,6 +180,12 @@
BranchSubViews.emplace_back(Line, Regions, std::move(View));
}
+void SourceCoverageView::addMCDCRecord(
+ unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View) {
+ MCDCSubViews.emplace_back(Line, Records, std::move(View));
+}
+
void SourceCoverageView::addInstantiation(
StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View) {
@@ -199,12 +211,15 @@
llvm::stable_sort(ExpansionSubViews);
llvm::stable_sort(InstantiationSubViews);
llvm::stable_sort(BranchSubViews);
+ llvm::stable_sort(MCDCSubViews);
auto NextESV = ExpansionSubViews.begin();
auto EndESV = ExpansionSubViews.end();
auto NextISV = InstantiationSubViews.begin();
auto EndISV = InstantiationSubViews.end();
auto NextBRV = BranchSubViews.begin();
auto EndBRV = BranchSubViews.end();
+ auto NextMSV = MCDCSubViews.begin();
+ auto EndMSV = MCDCSubViews.end();
// Get the coverage information for the file.
auto StartSegment = CoverageInfo.begin();
@@ -272,6 +287,11 @@
renderBranchView(OS, *NextBRV, ViewDepth + 1);
RenderedSubView = true;
}
+ for (; NextMSV != EndMSV && NextMSV->Line == LI.line_number(); ++NextMSV) {
+ renderViewDivider(OS, ViewDepth + 1);
+ renderMCDCView(OS, *NextMSV, ViewDepth + 1);
+ RenderedSubView = true;
+ }
if (RenderedSubView)
renderViewDivider(OS, ViewDepth + 1);
renderLineSuffix(OS, ViewDepth);
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.h b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.h
index 5a9fcdd..2e3fa8e 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -84,6 +84,23 @@
}
};
+/// A view that represents one or more MCDC regions on a given source line.
+struct MCDCView {
+ std::vector<MCDCRecord> Records;
+ std::unique_ptr<SourceCoverageView> View;
+ unsigned Line;
+
+ MCDCView(unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View)
+ : Records(Records), View(std::move(View)), Line(Line) {}
+
+ unsigned getLine() const { return Line; }
+
+ friend bool operator<(const MCDCView &LHS, const MCDCView &RHS) {
+ return LHS.Line < RHS.Line;
+ }
+};
+
/// A file manager that handles format-aware file creation.
class CoveragePrinter {
public:
@@ -99,7 +116,7 @@
CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {}
/// Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is
- /// false, skip the ToplevelDir component. If \p Relative is false, skip the
+ /// true, skip the ToplevelDir component. If \p Relative is true, skip the
/// OutputDir component.
std::string getOutputPath(StringRef Path, StringRef Extension,
bool InToplevel, bool Relative = true) const;
@@ -160,6 +177,9 @@
/// A container for all branches in the source on display.
std::vector<BranchView> BranchSubViews;
+ /// A container for all MCDC records in the source on display.
+ std::vector<MCDCView> MCDCSubViews;
+
/// A container for all instantiations (e.g template functions) in the source
/// on display.
std::vector<InstantiationView> InstantiationSubViews;
@@ -233,6 +253,10 @@
virtual void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) = 0;
+ /// Render an MCDC view.
+ virtual void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) = 0;
+
/// Render \p Title, a project title if one is available, and the
/// created time.
virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0;
@@ -283,6 +307,10 @@
void addBranch(unsigned Line, ArrayRef<CountedRegion> Regions,
std::unique_ptr<SourceCoverageView> View);
+ /// Add an MCDC subview to this view.
+ void addMCDCRecord(unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View);
+
/// Print the code coverage information for a specific portion of a
/// source file to the output stream.
void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 50e3dcc..b93d8cb 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -10,12 +10,13 @@
///
//===----------------------------------------------------------------------===//
-#include "CoverageReport.h"
#include "SourceCoverageViewHTML.h"
+#include "CoverageReport.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/ThreadPool.h"
#include <optional>
using namespace llvm;
@@ -49,23 +50,41 @@
}
// Create a \p Name tag around \p Str, and optionally set its \p ClassName.
-std::string tag(const std::string &Name, const std::string &Str,
- const std::string &ClassName = "") {
- std::string Tag = "<" + Name;
- if (!ClassName.empty())
- Tag += " class='" + ClassName + "'";
- return Tag + ">" + Str + "</" + Name + ">";
+std::string tag(StringRef Name, StringRef Str, StringRef ClassName = "") {
+ std::string Tag = "<";
+ Tag += Name;
+ if (!ClassName.empty()) {
+ Tag += " class='";
+ Tag += ClassName;
+ Tag += "'";
+ }
+ Tag += ">";
+ Tag += Str;
+ Tag += "</";
+ Tag += Name;
+ Tag += ">";
+ return Tag;
}
// Create an anchor to \p Link with the label \p Str.
-std::string a(const std::string &Link, const std::string &Str,
- const std::string &TargetName = "") {
- std::string Name = TargetName.empty() ? "" : ("name='" + TargetName + "' ");
- return "<a " + Name + "href='" + Link + "'>" + Str + "</a>";
+std::string a(StringRef Link, StringRef Str, StringRef TargetName = "") {
+ std::string Tag;
+ Tag += "<a ";
+ if (!TargetName.empty()) {
+ Tag += "name='";
+ Tag += TargetName;
+ Tag += "' ";
+ }
+ Tag += "href='";
+ Tag += Link;
+ Tag += "'>";
+ Tag += Str;
+ Tag += "</a>";
+ return Tag;
}
const char *BeginHeader =
- "<head>"
+ "<head>"
"<meta name='viewport' content='width=device-width,initial-scale=1'>"
"<meta charset='UTF-8'>";
@@ -111,10 +130,14 @@
.light-row {
background: #ffffff;
border: 1px solid #dbdbdb;
+ border-left: none;
+ border-right: none;
}
.light-row-bold {
background: #ffffff;
border: 1px solid #dbdbdb;
+ border-left: none;
+ border-right: none;
font-weight: bold;
}
.column-entry {
@@ -128,21 +151,28 @@
text-align: left;
background-color: #ffffd0;
}
-.column-entry-yellow:hover {
+.column-entry-yellow:hover, tr:hover .column-entry-yellow {
background-color: #fffff0;
}
.column-entry-red {
text-align: left;
background-color: #ffd0d0;
}
-.column-entry-red:hover {
+.column-entry-red:hover, tr:hover .column-entry-red {
background-color: #fff0f0;
}
+.column-entry-gray {
+ text-align: left;
+ background-color: #fbfbfb;
+}
+.column-entry-gray:hover, tr:hover .column-entry-gray {
+ background-color: #f0f0f0;
+}
.column-entry-green {
text-align: left;
background-color: #d0ffd0;
}
-.column-entry-green:hover {
+.column-entry-green:hover, tr:hover .column-entry-green {
background-color: #f0fff0;
}
.line-number {
@@ -213,6 +243,12 @@
tr:hover {
background-color: #f0f0f0;
}
+tr:last-child {
+ border-bottom: none;
+}
+tr:has(> td >a:target) > td.code > pre {
+ background-color: #ffa;
+}
)";
const char *EndHeader = "</head>";
@@ -272,6 +308,63 @@
OS << EndHeader << "<body>";
}
+void emitTableRow(raw_ostream &OS, const CoverageViewOptions &Opts,
+ const std::string &FirstCol, const FileCoverageSummary &FCS,
+ bool IsTotals) {
+ SmallVector<std::string, 8> Columns;
+
+ // Format a coverage triple and add the result to the list of columns.
+ auto AddCoverageTripleToColumn =
+ [&Columns, &Opts](unsigned Hit, unsigned Total, float Pctg) {
+ std::string S;
+ {
+ raw_string_ostream RSO{S};
+ if (Total)
+ RSO << format("%*.2f", 7, Pctg) << "% ";
+ else
+ RSO << "- ";
+ RSO << '(' << Hit << '/' << Total << ')';
+ }
+ const char *CellClass = "column-entry-yellow";
+ if (!Total)
+ CellClass = "column-entry-gray";
+ else if (Pctg >= Opts.HighCovWatermark)
+ CellClass = "column-entry-green";
+ else if (Pctg < Opts.LowCovWatermark)
+ CellClass = "column-entry-red";
+ Columns.emplace_back(tag("td", tag("pre", S), CellClass));
+ };
+
+ Columns.emplace_back(tag("td", tag("pre", FirstCol)));
+ AddCoverageTripleToColumn(FCS.FunctionCoverage.getExecuted(),
+ FCS.FunctionCoverage.getNumFunctions(),
+ FCS.FunctionCoverage.getPercentCovered());
+ if (Opts.ShowInstantiationSummary)
+ AddCoverageTripleToColumn(FCS.InstantiationCoverage.getExecuted(),
+ FCS.InstantiationCoverage.getNumFunctions(),
+ FCS.InstantiationCoverage.getPercentCovered());
+ AddCoverageTripleToColumn(FCS.LineCoverage.getCovered(),
+ FCS.LineCoverage.getNumLines(),
+ FCS.LineCoverage.getPercentCovered());
+ if (Opts.ShowRegionSummary)
+ AddCoverageTripleToColumn(FCS.RegionCoverage.getCovered(),
+ FCS.RegionCoverage.getNumRegions(),
+ FCS.RegionCoverage.getPercentCovered());
+ if (Opts.ShowBranchSummary)
+ AddCoverageTripleToColumn(FCS.BranchCoverage.getCovered(),
+ FCS.BranchCoverage.getNumBranches(),
+ FCS.BranchCoverage.getPercentCovered());
+ if (Opts.ShowMCDCSummary)
+ AddCoverageTripleToColumn(FCS.MCDCCoverage.getCoveredPairs(),
+ FCS.MCDCCoverage.getNumPairs(),
+ FCS.MCDCCoverage.getPercentCovered());
+
+ if (IsTotals)
+ OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row-bold");
+ else
+ OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row");
+}
+
void emitEpilog(raw_ostream &OS) {
OS << "</body>"
<< "</html>";
@@ -315,6 +408,8 @@
Columns.emplace_back(tag("td", "Region Coverage", "column-entry-bold"));
if (Opts.ShowBranchSummary)
Columns.emplace_back(tag("td", "Branch Coverage", "column-entry-bold"));
+ if (Opts.ShowMCDCSummary)
+ Columns.emplace_back(tag("td", "MC/DC", "column-entry-bold"));
OS << tag("tr", join(Columns.begin(), Columns.end(), ""));
}
@@ -330,71 +425,7 @@
return a(LinkTarget, LinkText);
}
-/// Render a file coverage summary (\p FCS) in a table row. If \p IsTotals is
-/// false, link the summary to \p SF.
-void CoveragePrinterHTML::emitFileSummary(raw_ostream &OS, StringRef SF,
- const FileCoverageSummary &FCS,
- bool IsTotals) const {
- SmallVector<std::string, 8> Columns;
-
- // Format a coverage triple and add the result to the list of columns.
- auto AddCoverageTripleToColumn =
- [&Columns, this](unsigned Hit, unsigned Total, float Pctg) {
- std::string S;
- {
- raw_string_ostream RSO{S};
- if (Total)
- RSO << format("%*.2f", 7, Pctg) << "% ";
- else
- RSO << "- ";
- RSO << '(' << Hit << '/' << Total << ')';
- }
- const char *CellClass = "column-entry-yellow";
- if (Pctg >= Opts.HighCovWatermark)
- CellClass = "column-entry-green";
- else if (Pctg < Opts.LowCovWatermark)
- CellClass = "column-entry-red";
- Columns.emplace_back(tag("td", tag("pre", S), CellClass));
- };
-
- // Simplify the display file path, and wrap it in a link if requested.
- std::string Filename;
- if (IsTotals) {
- Filename = std::string(SF);
- } else {
- Filename = buildLinkToFile(SF, FCS);
- }
-
- Columns.emplace_back(tag("td", tag("pre", Filename)));
- AddCoverageTripleToColumn(FCS.FunctionCoverage.getExecuted(),
- FCS.FunctionCoverage.getNumFunctions(),
- FCS.FunctionCoverage.getPercentCovered());
- if (Opts.ShowInstantiationSummary)
- AddCoverageTripleToColumn(FCS.InstantiationCoverage.getExecuted(),
- FCS.InstantiationCoverage.getNumFunctions(),
- FCS.InstantiationCoverage.getPercentCovered());
- AddCoverageTripleToColumn(FCS.LineCoverage.getCovered(),
- FCS.LineCoverage.getNumLines(),
- FCS.LineCoverage.getPercentCovered());
- if (Opts.ShowRegionSummary)
- AddCoverageTripleToColumn(FCS.RegionCoverage.getCovered(),
- FCS.RegionCoverage.getNumRegions(),
- FCS.RegionCoverage.getPercentCovered());
- if (Opts.ShowBranchSummary)
- AddCoverageTripleToColumn(FCS.BranchCoverage.getCovered(),
- FCS.BranchCoverage.getNumBranches(),
- FCS.BranchCoverage.getPercentCovered());
-
- if (IsTotals)
- OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row-bold");
- else
- OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row");
-}
-
-Error CoveragePrinterHTML::createIndexFile(
- ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
- const CoverageFiltersMatchAll &Filters) {
- // Emit the default stylesheet.
+Error CoveragePrinterHTML::emitStyleSheet() {
auto CSSOrErr = createOutputStream("style", "css", /*InToplevel=*/true);
if (Error E = CSSOrErr.takeError())
return E;
@@ -402,20 +433,15 @@
OwnedStream CSS = std::move(CSSOrErr.get());
CSS->operator<<(CSSForCoverage);
- // Emit a file index along with some coverage statistics.
- auto OSOrErr = createOutputStream("index", "html", /*InToplevel=*/true);
- if (Error E = OSOrErr.takeError())
- return E;
- auto OS = std::move(OSOrErr.get());
- raw_ostream &OSRef = *OS.get();
+ return Error::success();
+}
- assert(Opts.hasOutputDirectory() && "No output directory for index file");
- emitPrelude(OSRef, Opts, getPathToStyle(""));
-
+void CoveragePrinterHTML::emitReportHeader(raw_ostream &OSRef,
+ const std::string &Title) {
// Emit some basic information about the coverage report.
if (Opts.hasProjectTitle())
OSRef << tag(ProjectTitleTag, escape(Opts.ProjectTitle, Opts));
- OSRef << tag(ReportTitleTag, "Coverage Report");
+ OSRef << tag(ReportTitleTag, Title);
if (Opts.hasCreatedTime())
OSRef << tag(CreatedTimeTag, escape(Opts.CreatedTimeStr, Opts));
@@ -430,6 +456,43 @@
// Exclude files which don't contain any regions.
OSRef << BeginCenteredDiv << BeginTable;
emitColumnLabelsForIndex(OSRef, Opts);
+}
+
+/// Render a file coverage summary (\p FCS) in a table row. If \p IsTotals is
+/// false, link the summary to \p SF.
+void CoveragePrinterHTML::emitFileSummary(raw_ostream &OS, StringRef SF,
+ const FileCoverageSummary &FCS,
+ bool IsTotals) const {
+ // Simplify the display file path, and wrap it in a link if requested.
+ std::string Filename;
+ if (IsTotals) {
+ Filename = std::string(SF);
+ } else {
+ Filename = buildLinkToFile(SF, FCS);
+ }
+
+ emitTableRow(OS, Opts, Filename, FCS, IsTotals);
+}
+
+Error CoveragePrinterHTML::createIndexFile(
+ ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters) {
+ // Emit the default stylesheet.
+ if (Error E = emitStyleSheet())
+ return E;
+
+ // Emit a file index along with some coverage statistics.
+ auto OSOrErr = createOutputStream("index", "html", /*InToplevel=*/true);
+ if (Error E = OSOrErr.takeError())
+ return E;
+ auto OS = std::move(OSOrErr.get());
+ raw_ostream &OSRef = *OS.get();
+
+ assert(Opts.hasOutputDirectory() && "No output directory for index file");
+ emitPrelude(OSRef, Opts, getPathToStyle(""));
+
+ emitReportHeader(OSRef, "Coverage Report");
+
FileCoverageSummary Totals("TOTALS");
auto FileReports = CoverageReport::prepareFileReports(
Coverage, Totals, SourceFiles, Opts, Filters);
@@ -465,6 +528,199 @@
return Error::success();
}
+struct CoveragePrinterHTMLDirectory::Reporter : public DirectoryCoverageReport {
+ CoveragePrinterHTMLDirectory &Printer;
+
+ Reporter(CoveragePrinterHTMLDirectory &Printer,
+ const coverage::CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters)
+ : DirectoryCoverageReport(Printer.Opts, Coverage, Filters),
+ Printer(Printer) {}
+
+ Error generateSubDirectoryReport(SubFileReports &&SubFiles,
+ SubDirReports &&SubDirs,
+ FileCoverageSummary &&SubTotals) override {
+ auto &LCPath = SubTotals.Name;
+ assert(Options.hasOutputDirectory() &&
+ "No output directory for index file");
+
+ SmallString<128> OSPath = LCPath;
+ sys::path::append(OSPath, "index");
+ auto OSOrErr = Printer.createOutputStream(OSPath, "html",
+ /*InToplevel=*/false);
+ if (auto E = OSOrErr.takeError())
+ return E;
+ auto OS = std::move(OSOrErr.get());
+ raw_ostream &OSRef = *OS.get();
+
+ auto IndexHtmlPath = Printer.getOutputPath((LCPath + "index").str(), "html",
+ /*InToplevel=*/false);
+ emitPrelude(OSRef, Options, getPathToStyle(IndexHtmlPath));
+
+ auto NavLink = buildTitleLinks(LCPath);
+ Printer.emitReportHeader(OSRef, "Coverage Report (" + NavLink + ")");
+
+ std::vector<const FileCoverageSummary *> EmptyFiles;
+
+ // Make directories at the top of the table.
+ for (auto &&SubDir : SubDirs) {
+ auto &Report = SubDir.second.first;
+ if (!Report.FunctionCoverage.getNumFunctions())
+ EmptyFiles.push_back(&Report);
+ else
+ emitTableRow(OSRef, Options, buildRelLinkToFile(Report.Name), Report,
+ /*IsTotals=*/false);
+ }
+
+ for (auto &&SubFile : SubFiles) {
+ auto &Report = SubFile.second;
+ if (!Report.FunctionCoverage.getNumFunctions())
+ EmptyFiles.push_back(&Report);
+ else
+ emitTableRow(OSRef, Options, buildRelLinkToFile(Report.Name), Report,
+ /*IsTotals=*/false);
+ }
+
+ // Emit the totals row.
+ emitTableRow(OSRef, Options, "Totals", SubTotals, /*IsTotals=*/false);
+ OSRef << EndTable << EndCenteredDiv;
+
+ // Emit links to files which don't contain any functions. These are normally
+ // not very useful, but could be relevant for code which abuses the
+ // preprocessor.
+ if (!EmptyFiles.empty()) {
+ OSRef << tag("p", "Files which contain no functions. (These "
+ "files contain code pulled into other files "
+ "by the preprocessor.)\n");
+ OSRef << BeginCenteredDiv << BeginTable;
+ for (auto FCS : EmptyFiles) {
+ auto Link = buildRelLinkToFile(FCS->Name);
+ OSRef << tag("tr", tag("td", tag("pre", Link)), "light-row") << '\n';
+ }
+ OSRef << EndTable << EndCenteredDiv;
+ }
+
+ // Emit epilog.
+ OSRef << tag("h5", escape(Options.getLLVMVersionString(), Options));
+ emitEpilog(OSRef);
+
+ return Error::success();
+ }
+
+ /// Make a title with hyperlinks to the index.html files of each hierarchy
+ /// of the report.
+ std::string buildTitleLinks(StringRef LCPath) const {
+ // For each report level in LCPStack, extract the path component and
+ // calculate the number of "../" relative to current LCPath.
+ SmallVector<std::pair<SmallString<128>, unsigned>, 16> Components;
+
+ auto Iter = LCPStack.begin(), IterE = LCPStack.end();
+ SmallString<128> RootPath;
+ if (*Iter == 0) {
+ // If llvm-cov works on relative coverage mapping data, the LCP of
+ // all source file paths can be 0, which makes the title path empty.
+ // As we like adding a slash at the back of the path to indicate a
+ // directory, in this case, we use "." as the root path to make it
+ // not be confused with the root path "/".
+ RootPath = ".";
+ } else {
+ RootPath = LCPath.substr(0, *Iter);
+ sys::path::native(RootPath);
+ sys::path::remove_dots(RootPath, /*remove_dot_dot=*/true);
+ }
+ Components.emplace_back(std::move(RootPath), 0);
+
+ for (auto Last = *Iter; ++Iter != IterE; Last = *Iter) {
+ SmallString<128> SubPath = LCPath.substr(Last, *Iter - Last);
+ sys::path::native(SubPath);
+ sys::path::remove_dots(SubPath, /*remove_dot_dot=*/true);
+ auto Level = unsigned(SubPath.count(sys::path::get_separator())) + 1;
+ Components.back().second += Level;
+ Components.emplace_back(std::move(SubPath), Level);
+ }
+
+ // Then we make the title accroding to Components.
+ std::string S;
+ for (auto I = Components.begin(), E = Components.end();;) {
+ auto &Name = I->first;
+ if (++I == E) {
+ S += a("./index.html", Name);
+ S += sys::path::get_separator();
+ break;
+ }
+
+ SmallString<128> Link;
+ for (unsigned J = I->second; J > 0; --J)
+ Link += "../";
+ Link += "index.html";
+ S += a(Link, Name);
+ S += sys::path::get_separator();
+ }
+ return S;
+ }
+
+ std::string buildRelLinkToFile(StringRef RelPath) const {
+ SmallString<128> LinkTextStr(RelPath);
+ sys::path::native(LinkTextStr);
+
+ // remove_dots will remove trailing slash, so we need to check before it.
+ auto IsDir = LinkTextStr.ends_with(sys::path::get_separator());
+ sys::path::remove_dots(LinkTextStr, /*remove_dot_dot=*/true);
+
+ SmallString<128> LinkTargetStr(LinkTextStr);
+ if (IsDir) {
+ LinkTextStr += sys::path::get_separator();
+ sys::path::append(LinkTargetStr, "index.html");
+ } else {
+ LinkTargetStr += ".html";
+ }
+
+ auto LinkText = escape(LinkTextStr, Options);
+ auto LinkTarget = escape(LinkTargetStr, Options);
+ return a(LinkTarget, LinkText);
+ }
+};
+
+Error CoveragePrinterHTMLDirectory::createIndexFile(
+ ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters) {
+ // The createSubIndexFile function only works when SourceFiles is
+ // more than one. So we fallback to CoveragePrinterHTML when it is.
+ if (SourceFiles.size() <= 1)
+ return CoveragePrinterHTML::createIndexFile(SourceFiles, Coverage, Filters);
+
+ // Emit the default stylesheet.
+ if (Error E = emitStyleSheet())
+ return E;
+
+ // Emit index files in every subdirectory.
+ Reporter Report(*this, Coverage, Filters);
+ auto TotalsOrErr = Report.prepareDirectoryReports(SourceFiles);
+ if (auto E = TotalsOrErr.takeError())
+ return E;
+ auto &LCPath = TotalsOrErr->Name;
+
+ // Emit the top level index file. Top level index file is just a redirection
+ // to the index file in the LCP directory.
+ auto OSOrErr = createOutputStream("index", "html", /*InToplevel=*/true);
+ if (auto E = OSOrErr.takeError())
+ return E;
+ auto OS = std::move(OSOrErr.get());
+ auto LCPIndexFilePath =
+ getOutputPath((LCPath + "index").str(), "html", /*InToplevel=*/false);
+ *OS.get() << R"(<!DOCTYPE html>
+ <html>
+ <head>
+ <meta http-equiv="Refresh" content="0; url=')"
+ << LCPIndexFilePath << R"('" />
+ </head>
+ <body></body>
+ </html>
+ )";
+
+ return Error::success();
+}
+
void SourceCoverageViewHTML::renderViewHeader(raw_ostream &OS) {
OS << BeginCenteredDiv << BeginTable;
}
@@ -668,7 +924,9 @@
// Calculate TruePercent and False Percent.
double TruePercent = 0.0;
double FalsePercent = 0.0;
- unsigned Total = R.ExecutionCount + R.FalseExecutionCount;
+ // FIXME: It may overflow when the data is too large, but I have not
+ // encountered it in actual use, and not sure whether to use __uint128_t.
+ uint64_t Total = R.ExecutionCount + R.FalseExecutionCount;
if (!getOptions().ShowBranchCounts && Total != 0) {
TruePercent = ((double)(R.ExecutionCount) / (double)Total) * 100.0;
@@ -722,6 +980,50 @@
OS << EndExpansionDiv;
}
+void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
+ unsigned ViewDepth) {
+ for (auto &Record : MRV.Records) {
+ OS << BeginExpansionDiv;
+ OS << BeginPre;
+ OS << " MC/DC Decision Region (";
+
+ // Display Line + Column information.
+ const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
+ std::string LineNoStr = Twine(DecisionRegion.LineStart).str();
+ std::string ColNoStr = Twine(DecisionRegion.ColumnStart).str();
+ std::string TargetName = "L" + LineNoStr;
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr)),
+ "line-number") +
+ ") to (";
+ LineNoStr = utostr(uint64_t(DecisionRegion.LineEnd));
+ ColNoStr = utostr(uint64_t(DecisionRegion.ColumnEnd));
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr)),
+ "line-number") +
+ ")\n\n";
+
+ // Display MC/DC Information.
+ OS << " Number of Conditions: " << Record.getNumConditions() << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ OS << " " << Record.getConditionHeaderString(i);
+ }
+ OS << "\n";
+ OS << " Executed MC/DC Test Vectors:\n\n ";
+ OS << Record.getTestVectorHeaderString();
+ for (unsigned i = 0; i < Record.getNumTestVectors(); i++)
+ OS << Record.getTestVectorString(i);
+ OS << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++)
+ OS << Record.getConditionCoverageString(i);
+ OS << " MC/DC Coverage for Expression: ";
+ OS << format("%0.2f", Record.getPercentCovered()) << "%\n";
+ OS << EndPre;
+ OS << EndExpansionDiv;
+ }
+ return;
+}
+
void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.h b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
index 7d94675..7b97f05 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -19,6 +19,8 @@
using namespace coverage;
+class ThreadPool;
+
struct FileCoverageSummary;
/// A coverage printer for html output.
@@ -36,6 +38,10 @@
CoveragePrinterHTML(const CoverageViewOptions &Opts)
: CoveragePrinter(Opts) {}
+protected:
+ Error emitStyleSheet();
+ void emitReportHeader(raw_ostream &OSRef, const std::string &Title);
+
private:
void emitFileSummary(raw_ostream &OS, StringRef SF,
const FileCoverageSummary &FCS,
@@ -44,6 +50,20 @@
const FileCoverageSummary &FCS) const;
};
+/// A coverage printer for html output, but generates index files in every
+/// subdirectory to show a hierarchical view.
+class CoveragePrinterHTMLDirectory : public CoveragePrinterHTML {
+public:
+ using CoveragePrinterHTML::CoveragePrinterHTML;
+
+ Error createIndexFile(ArrayRef<std::string> SourceFiles,
+ const coverage::CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters) override;
+
+private:
+ struct Reporter;
+};
+
/// A code coverage view which supports html-based rendering.
class SourceCoverageViewHTML : public SourceCoverageView {
void renderViewHeader(raw_ostream &OS) override;
@@ -71,6 +91,9 @@
void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) override;
+ void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 40d4359..580da45 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -14,7 +14,9 @@
#include "CoverageReport.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
#include <optional>
using namespace llvm;
@@ -46,6 +48,69 @@
return Error::success();
}
+struct CoveragePrinterTextDirectory::Reporter : public DirectoryCoverageReport {
+ CoveragePrinterTextDirectory &Printer;
+
+ Reporter(CoveragePrinterTextDirectory &Printer,
+ const coverage::CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters)
+ : DirectoryCoverageReport(Printer.Opts, Coverage, Filters),
+ Printer(Printer) {}
+
+ Error generateSubDirectoryReport(SubFileReports &&SubFiles,
+ SubDirReports &&SubDirs,
+ FileCoverageSummary &&SubTotals) override {
+ auto &LCPath = SubTotals.Name;
+ assert(Options.hasOutputDirectory() &&
+ "No output directory for index file");
+
+ SmallString<128> OSPath = LCPath;
+ sys::path::append(OSPath, "index");
+ auto OSOrErr = Printer.createOutputStream(OSPath, "txt",
+ /*InToplevel=*/false);
+ if (auto E = OSOrErr.takeError())
+ return E;
+ auto OS = std::move(OSOrErr.get());
+ raw_ostream &OSRef = *OS.get();
+
+ std::vector<FileCoverageSummary> Reports;
+ for (auto &&SubDir : SubDirs)
+ Reports.push_back(std::move(SubDir.second.first));
+ for (auto &&SubFile : SubFiles)
+ Reports.push_back(std::move(SubFile.second));
+
+ CoverageReport Report(Options, Coverage);
+ Report.renderFileReports(OSRef, Reports, SubTotals, Filters.empty());
+
+ Options.colored_ostream(OSRef, raw_ostream::CYAN)
+ << "\n"
+ << Options.getLLVMVersionString();
+
+ return Error::success();
+ }
+};
+
+Error CoveragePrinterTextDirectory::createIndexFile(
+ ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters) {
+ if (SourceFiles.size() <= 1)
+ return CoveragePrinterText::createIndexFile(SourceFiles, Coverage, Filters);
+
+ Reporter Report(*this, Coverage, Filters);
+ auto TotalsOrErr = Report.prepareDirectoryReports(SourceFiles);
+ if (auto E = TotalsOrErr.takeError())
+ return E;
+ auto &LCPath = TotalsOrErr->Name;
+
+ auto TopIndexFilePath =
+ getOutputPath("index", "txt", /*InToplevel=*/true, /*Relative=*/false);
+ auto LCPIndexFilePath =
+ getOutputPath((LCPath + "index").str(), "txt", /*InToplevel=*/false,
+ /*Relative=*/false);
+ return errorCodeToError(
+ sys::fs::copy_file(LCPIndexFilePath, TopIndexFilePath));
+}
+
namespace {
static const unsigned LineCoverageColumnWidth = 7;
@@ -232,7 +297,9 @@
for (const auto &R : BRV.Regions) {
double TruePercent = 0.0;
double FalsePercent = 0.0;
- unsigned Total = R.ExecutionCount + R.FalseExecutionCount;
+ // FIXME: It may overflow when the data is too large, but I have not
+ // encountered it in actual use, and not sure whether to use __uint128_t.
+ uint64_t Total = R.ExecutionCount + R.FalseExecutionCount;
if (!getOptions().ShowBranchCounts && Total != 0) {
TruePercent = ((double)(R.ExecutionCount) / (double)Total) * 100.0;
@@ -270,6 +337,58 @@
}
}
+void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
+ unsigned ViewDepth) {
+ for (auto &Record : MRV.Records) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << "---> MC/DC Decision Region (";
+ // Display Line + Column information.
+ const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
+ OS << DecisionRegion.LineStart << ":";
+ OS << DecisionRegion.ColumnStart << ") to (";
+ OS << DecisionRegion.LineEnd << ":";
+ OS << DecisionRegion.ColumnEnd << ")\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+
+ // Display MC/DC Information.
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Number of Conditions: " << Record.getNumConditions() << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << " " << Record.getConditionHeaderString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Executed MC/DC Test Vectors:\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << " ";
+ OS << Record.getTestVectorHeaderString();
+ for (unsigned i = 0; i < Record.getNumTestVectors(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << Record.getTestVectorString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << Record.getConditionCoverageString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << " MC/DC Coverage for Decision: ";
+ colored_ostream(OS, raw_ostream::RED,
+ getOptions().Colors && Record.getPercentCovered() < 100.0,
+ /*Bold=*/false, /*BG=*/true)
+ << format("%0.2f", Record.getPercentCovered()) << "%";
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ }
+}
+
void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.h b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.h
index b2be060..7cb47fc 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -35,6 +35,21 @@
: CoveragePrinter(Opts) {}
};
+/// A coverage printer for text output, but generates index files in every
+/// subdirectory to show a hierarchical view. The implementation is similar
+/// to CoveragePrinterHTMLDirectory. So please refer to that for more comments.
+class CoveragePrinterTextDirectory : public CoveragePrinterText {
+public:
+ using CoveragePrinterText::CoveragePrinterText;
+
+ Error createIndexFile(ArrayRef<std::string> SourceFiles,
+ const CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters) override;
+
+private:
+ struct Reporter;
+};
+
/// A code coverage view which supports text-based rendering.
class SourceCoverageViewText : public SourceCoverageView {
void renderViewHeader(raw_ostream &OS) override;
@@ -62,6 +77,9 @@
void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) override;
+ void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;
diff --git a/src/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp b/src/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp
index 289a162..6ad8c35 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp
@@ -6,7 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/CommandLine.h"
@@ -51,6 +53,28 @@
int FoundSectionCount = 0;
SectionRef ProfileNames, CoverageMapping, CoverageRecords;
auto ObjFormat = OF->getTripleObjectFormat();
+
+ auto ProfileNamesSection = getInstrProfSectionName(IPSK_name, ObjFormat,
+ /*AddSegmentInfo=*/false);
+ auto CoverageMappingSection =
+ getInstrProfSectionName(IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false);
+ auto CoverageRecordsSection =
+ getInstrProfSectionName(IPSK_covfun, ObjFormat, /*AddSegmentInfo=*/false);
+ if (isa<object::COFFObjectFile>(OF)) {
+ // On COFF, the object file section name may end in "$M". This tells the
+ // linker to sort these sections between "$A" and "$Z". The linker removes
+ // the dollar and everything after it in the final binary. Do the same to
+ // match.
+ auto Strip = [](std::string &Str) {
+ auto Pos = Str.find('$');
+ if (Pos != std::string::npos)
+ Str.resize(Pos);
+ };
+ Strip(ProfileNamesSection);
+ Strip(CoverageMappingSection);
+ Strip(CoverageRecordsSection);
+ }
+
for (const auto &Section : OF->sections()) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Section.getName()) {
@@ -60,16 +84,13 @@
return 1;
}
- if (Name == llvm::getInstrProfSectionName(IPSK_name, ObjFormat,
- /*AddSegmentInfo=*/false)) {
+ if (Name == ProfileNamesSection)
ProfileNames = Section;
- } else if (Name == llvm::getInstrProfSectionName(
- IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)) {
+ else if (Name == CoverageMappingSection)
CoverageMapping = Section;
- } else if (Name == llvm::getInstrProfSectionName(
- IPSK_covfun, ObjFormat, /*AddSegmentInfo=*/false)) {
+ else if (Name == CoverageRecordsSection)
CoverageRecords = Section;
- } else
+ else
continue;
++FoundSectionCount;
}
@@ -100,25 +121,22 @@
return 1;
}
+ // If this is a linked PE/COFF file, then we have to skip over the null byte
+ // that is allocated in the .lprfn$A section in the LLVM profiling runtime.
+ if (isa<COFFObjectFile>(OF) && !OF->isRelocatableObject())
+ ProfileNamesData = ProfileNamesData.drop_front(1);
+
int FD;
if (auto Err = sys::fs::openFileForWrite(OutputFilename, FD)) {
errs() << "error: " << Err.message() << "\n";
return 1;
}
+ coverage::TestingFormatWriter Writer(ProfileNamesAddress, ProfileNamesData,
+ CoverageMappingData,
+ CoverageRecordsData);
raw_fd_ostream OS(FD, true);
- OS << "llvmcovmtestdata";
- encodeULEB128(ProfileNamesData.size(), OS);
- encodeULEB128(ProfileNamesAddress, OS);
- OS << ProfileNamesData;
- // Coverage mapping data is expected to have an alignment of 8.
- for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad)
- OS.write(uint8_t(0));
- OS << CoverageMappingData;
- // Coverage records data is expected to have an alignment of 8.
- for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad)
- OS.write(uint8_t(0));
- OS << CoverageRecordsData;
+ Writer.write(OS);
return 0;
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/gcov.cpp b/src/llvm-project/llvm/tools/llvm-cov/gcov.cpp
index 9a1ebeb..00ea124 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/gcov.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/gcov.cpp
@@ -35,12 +35,10 @@
// A file was given. Ignore the source file and look next to this file.
sys::path::replace_extension(CoverageFileStem, "");
- std::string GCNO = InputGCNO.empty()
- ? std::string(CoverageFileStem.str()) + ".gcno"
- : InputGCNO;
- std::string GCDA = InputGCDA.empty()
- ? std::string(CoverageFileStem.str()) + ".gcda"
- : InputGCDA;
+ std::string GCNO =
+ InputGCNO.empty() ? std::string(CoverageFileStem) + ".gcno" : InputGCNO;
+ std::string GCDA =
+ InputGCDA.empty() ? std::string(CoverageFileStem) + ".gcda" : InputGCDA;
GCOVFile GF;
// Open .gcda and .gcda without requiring a NUL terminator. The concurrent
diff --git a/src/llvm-project/llvm/tools/llvm-cvtres/llvm-cvtres.cpp b/src/llvm-project/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
index 9040237..0c10769 100644
--- a/src/llvm-project/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
@@ -37,9 +37,7 @@
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -51,14 +49,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
diff --git a/src/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp b/src/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
index f35f626..c04aec1 100644
--- a/src/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
@@ -217,7 +217,7 @@
// VFTables in the MS-ABI start with '??_7' and are contained within their
// own COMDAT section. We then determine the contents of the VFTable by
// looking at each relocation in the section.
- if (SymName.startswith("??_7")) {
+ if (SymName.starts_with("??_7")) {
// Each relocation either names a virtual method or a thunk. We note the
// offset into the section and the symbol used for the relocation.
collectRelocationOffsets(Obj, Sec, SecAddress, SecAddress, SecSize,
@@ -225,14 +225,14 @@
}
// VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
// offsets of virtual bases.
- else if (SymName.startswith("??_8")) {
+ else if (SymName.starts_with("??_8")) {
ArrayRef<little32_t> VBTableData(
reinterpret_cast<const little32_t *>(SymContents.data()),
SymContents.size() / sizeof(little32_t));
VBTables[SymName] = VBTableData;
}
// Complete object locators in the MS-ABI start with '??_R4'
- else if (SymName.startswith("??_R4")) {
+ else if (SymName.starts_with("??_R4")) {
CompleteObjectLocator COL;
COL.Data =
ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);
@@ -241,7 +241,7 @@
COLs[SymName] = COL;
}
// Class hierarchy descriptors in the MS-ABI start with '??_R3'
- else if (SymName.startswith("??_R3")) {
+ else if (SymName.starts_with("??_R3")) {
ClassHierarchyDescriptor CHD;
CHD.Data =
ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);
@@ -250,14 +250,14 @@
CHDs[SymName] = CHD;
}
// Class hierarchy descriptors in the MS-ABI start with '??_R2'
- else if (SymName.startswith("??_R2")) {
+ else if (SymName.starts_with("??_R2")) {
// Each relocation names a base class descriptor. We note the offset into
// the section and the symbol used for the relocation.
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
SymName, BCAEntries);
}
// Base class descriptors in the MS-ABI start with '??_R1'
- else if (SymName.startswith("??_R1")) {
+ else if (SymName.starts_with("??_R1")) {
BaseClassDescriptor BCD;
BCD.Data = ArrayRef(
reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5);
@@ -266,7 +266,7 @@
BCDs[SymName] = BCD;
}
// Type descriptors in the MS-ABI start with '??_R0'
- else if (SymName.startswith("??_R0")) {
+ else if (SymName.starts_with("??_R0")) {
const char *DataPtr = SymContents.drop_front(BytesInAddress).data();
TypeDescriptor TD;
if (BytesInAddress == 8)
@@ -279,7 +279,7 @@
TDs[SymName] = TD;
}
// Throw descriptors in the MS-ABI start with '_TI'
- else if (SymName.startswith("_TI") || SymName.startswith("__TI")) {
+ else if (SymName.starts_with("_TI") || SymName.starts_with("__TI")) {
ThrowInfo TI;
TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data());
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
@@ -287,7 +287,7 @@
TIs[SymName] = TI;
}
// Catchable type arrays in the MS-ABI start with _CTA or __CTA.
- else if (SymName.startswith("_CTA") || SymName.startswith("__CTA")) {
+ else if (SymName.starts_with("_CTA") || SymName.starts_with("__CTA")) {
CatchableTypeArray CTA;
CTA.NumEntries =
*reinterpret_cast<const little32_t *>(SymContents.data());
@@ -296,7 +296,7 @@
CTAs[SymName] = CTA;
}
// Catchable types in the MS-ABI start with _CT or __CT.
- else if (SymName.startswith("_CT") || SymName.startswith("__CT")) {
+ else if (SymName.starts_with("_CT") || SymName.starts_with("__CT")) {
const little32_t *DataPtr =
reinterpret_cast<const little32_t *>(SymContents.data());
CatchableType CT;
@@ -310,16 +310,16 @@
CTs[SymName] = CT;
}
// Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
- else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) {
+ else if (SymName.starts_with("_ZTT") || SymName.starts_with("__ZTT")) {
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
SymName, VTTEntries);
}
// Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.
- else if (SymName.startswith("_ZTS") || SymName.startswith("__ZTS")) {
+ else if (SymName.starts_with("_ZTS") || SymName.starts_with("__ZTS")) {
TINames[SymName] = SymContents.slice(0, SymContents.find('\0'));
}
// Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.
- else if (SymName.startswith("_ZTV") || SymName.startswith("__ZTV")) {
+ else if (SymName.starts_with("_ZTV") || SymName.starts_with("__ZTV")) {
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
SymName, VTableSymEntries);
for (uint64_t SymOffI = 0; SymOffI < SymSize; SymOffI += BytesInAddress) {
@@ -337,7 +337,7 @@
}
}
// Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.
- else if (SymName.startswith("_ZTI") || SymName.startswith("__ZTI")) {
+ else if (SymName.starts_with("_ZTI") || SymName.starts_with("__ZTI")) {
// FIXME: Do something with these!
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-cxxfilt/Opts.td b/src/llvm-project/llvm/tools/llvm-cxxfilt/Opts.td
index f652a1a..034cb26 100644
--- a/src/llvm-project/llvm/tools/llvm-cxxfilt/Opts.td
+++ b/src/llvm-project/llvm/tools/llvm-cxxfilt/Opts.td
@@ -17,6 +17,7 @@
def help : FF<"help", "Display this help">;
defm strip_underscore : BB<"strip-underscore", "Strip the leading underscore", "Don't strip the leading underscore">;
def types : FF<"types", "Attempt to demangle types as well as function names">;
+def no_params : FF<"no-params", "Skip function parameters and return types">;
def version : FF<"version", "Display the version">;
defm : Eq<"format", "Specify mangling format. Currently ignored because only 'gnu' is supported">;
@@ -25,4 +26,5 @@
def : F<"_", "Alias for --strip-underscore">, Alias<strip_underscore>;
def : F<"h", "Alias for --help">, Alias<help>;
def : F<"n", "Alias for --no-strip-underscore">, Alias<no_strip_underscore>;
+def : F<"p", "Alias for --no-params">, Alias<no_params>;
def : F<"t", "Alias for --types">, Alias<types>;
diff --git a/src/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/src/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index 2bbd57f..d63f507 100644
--- a/src/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -13,7 +13,6 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
@@ -27,9 +26,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -41,14 +38,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -61,6 +53,7 @@
};
} // namespace
+static bool ParseParams;
static bool StripUnderscore;
static bool Types;
@@ -74,23 +67,26 @@
static std::string demangle(const std::string &Mangled) {
using llvm::itanium_demangle::starts_with;
std::string_view DecoratedStr = Mangled;
- if (StripUnderscore)
- if (DecoratedStr[0] == '_')
- DecoratedStr.remove_prefix(1);
+ bool CanHaveLeadingDot = true;
+ if (StripUnderscore && DecoratedStr[0] == '_') {
+ DecoratedStr.remove_prefix(1);
+ CanHaveLeadingDot = false;
+ }
std::string Result;
- if (nonMicrosoftDemangle(DecoratedStr, Result))
+ if (nonMicrosoftDemangle(DecoratedStr, Result, CanHaveLeadingDot,
+ ParseParams))
return Result;
std::string Prefix;
char *Undecorated = nullptr;
if (Types)
- Undecorated = itaniumDemangle(DecoratedStr);
+ Undecorated = itaniumDemangle(DecoratedStr, ParseParams);
if (!Undecorated && starts_with(DecoratedStr, "__imp_")) {
Prefix = "import thunk for ";
- Undecorated = itaniumDemangle(DecoratedStr.substr(6));
+ Undecorated = itaniumDemangle(DecoratedStr.substr(6), ParseParams);
}
Result = Undecorated ? Prefix + Undecorated : Mangled;
@@ -149,7 +145,6 @@
}
int llvm_cxxfilt_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
CxxfiltOptTable Tbl;
@@ -178,6 +173,8 @@
else
StripUnderscore = Triple(sys::getProcessTriple()).isOSBinFormatMachO();
+ ParseParams = !Args.hasArg(OPT_no_params);
+
Types = Args.hasArg(OPT_types);
std::vector<std::string> Decorated = Args.getAllArgValues(OPT_INPUT);
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp b/src/llvm-project/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
index a9b3452..425ee8d 100644
--- a/src/llvm-project/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
+++ b/src/llvm-project/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
@@ -123,6 +123,6 @@
DebuginfodFetcher(DebugFileDirectory).fetch(BuildID))
return *Path;
errs() << "Build ID " << llvm::toHex(BuildID, /*Lowercase=*/true)
- << " could not be found.";
+ << " could not be found.\n";
exit(1);
}
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfod/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-debuginfod/CMakeLists.txt
index d32c682..6b0a119 100644
--- a/src/llvm-project/llvm/tools/llvm-debuginfod/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-debuginfod/CMakeLists.txt
@@ -11,8 +11,13 @@
DEPENDS
DebugInfodOptsTableGen
+ GENERATE_DRIVER
)
-target_link_libraries(llvm-debuginfod PRIVATE LLVMDebuginfod)
+
+if(NOT LLVM_TOOL_LLVM_DRIVER_BUILD)
+ target_link_libraries(llvm-debuginfod PRIVATE LLVMDebuginfod)
+endif()
+
if(LLVM_INSTALL_BINUTILS_SYMLINKS)
add_llvm_tool_symlink(debuginfod llvm-debuginfod)
endif()
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp b/src/llvm-project/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
index 725b810..9d347db 100644
--- a/src/llvm-project/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
+++ b/src/llvm-project/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
@@ -22,7 +22,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/ThreadPool.h"
using namespace llvm;
@@ -31,9 +31,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -45,14 +43,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -126,8 +119,7 @@
HostInterface = Args.getLastArgValue(OPT_host_interface, "0.0.0.0");
}
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
+int llvm_debuginfod_main(int argc, char **argv, const llvm::ToolContext &) {
HTTPClient::initialize();
parseArgs(argc, argv);
diff --git a/src/llvm-project/llvm/tools/llvm-diff/lib/DifferenceEngine.cpp b/src/llvm-project/llvm/tools/llvm-diff/lib/DifferenceEngine.cpp
index 6573bf0..64b5051 100644
--- a/src/llvm-project/llvm/tools/llvm-diff/lib/DifferenceEngine.cpp
+++ b/src/llvm-project/llvm/tools/llvm-diff/lib/DifferenceEngine.cpp
@@ -214,11 +214,9 @@
};
unsigned getUnprocPredCount(const BasicBlock *Block) const {
- unsigned Count = 0;
- for (const_pred_iterator I = pred_begin(Block), E = pred_end(Block); I != E;
- ++I)
- if (!Blocks.count(*I)) Count++;
- return Count;
+ return llvm::count_if(predecessors(Block), [&](const BasicBlock *Pred) {
+ return !Blocks.contains(Pred);
+ });
}
typedef std::pair<const BasicBlock *, const BasicBlock *> BlockPair;
@@ -791,9 +789,9 @@
};
struct DiffEntry {
- DiffEntry() : Cost(0) {}
+ DiffEntry() = default;
- unsigned Cost;
+ unsigned Cost = 0;
llvm::SmallVector<char, 8> Path; // actually of DifferenceEngine::DiffChange
};
diff --git a/src/llvm-project/llvm/tools/llvm-diff/llvm-diff.cpp b/src/llvm-project/llvm/tools/llvm-diff/llvm-diff.cpp
index 7349469..3e77b1e 100644
--- a/src/llvm-project/llvm/tools/llvm-diff/llvm-diff.cpp
+++ b/src/llvm-project/llvm/tools/llvm-diff/llvm-diff.cpp
@@ -42,7 +42,7 @@
static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R,
StringRef Name) {
// Drop leading sigils from the global name.
- if (Name.startswith("@")) Name = Name.substr(1);
+ Name.consume_front("@");
Function *LFn = L.getFunction(Name);
Function *RFn = R.getFunction(Name);
diff --git a/src/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp b/src/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp
index 4996fc1..06fc669 100644
--- a/src/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp
@@ -225,7 +225,7 @@
FinalFilename = "-";
} else {
StringRef IFN = InputFilename;
- FinalFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str();
+ FinalFilename = (IFN.ends_with(".bc") ? IFN.drop_back(3) : IFN).str();
if (N > 1)
FinalFilename += std::string(".") + std::to_string(I);
FinalFilename += ".ll";
diff --git a/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt
index 23cc373..83e0840 100644
--- a/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt
@@ -25,6 +25,7 @@
set_target_properties(llvm-driver PROPERTIES OUTPUT_NAME llvm)
target_link_libraries(llvm-driver PUBLIC ${LLVM_DRIVER_OBJLIBS})
+target_link_libraries(llvm-driver PUBLIC LLVMDebuginfod)
if(APPLE)
# dsymutil uses some CoreFoundation stuff on Darwin...
diff --git a/src/llvm-project/llvm/tools/llvm-driver/llvm-driver.cpp b/src/llvm-project/llvm/tools/llvm-driver/llvm-driver.cpp
index a0f1ca8..53a8b935 100644
--- a/src/llvm-project/llvm/tools/llvm-driver/llvm-driver.cpp
+++ b/src/llvm-project/llvm/tools/llvm-driver/llvm-driver.cpp
@@ -10,6 +10,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/WithColor.h"
@@ -79,4 +80,7 @@
return 1;
}
-int main(int Argc, char **Argv) { return findTool(Argc, Argv, Argv[0]); }
+int main(int Argc, char **Argv) {
+ llvm::InitLLVM X(Argc, Argv);
+ return findTool(Argc, Argv, Argv[0]);
+}
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp b/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp
index a967abf..96841c3 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -319,7 +319,7 @@
auto Offset = Die.find(dwarf::DW_AT_abstract_origin);
// Do not track this variable any more, since it has location
// coverage.
- llvm::erase_value(*AbstractOriginVariables, (*Offset).getRawUValue());
+ llvm::erase(*AbstractOriginVariables, (*Offset).getRawUValue());
}
} else {
// The locstats will be handled at the end of
@@ -743,7 +743,7 @@
Child.find(dwarf::DW_AT_const_value))) {
auto OffsetVar = Child.find(dwarf::DW_AT_abstract_origin);
if (OffsetVar)
- llvm::erase_value(AbstractOriginVars, (*OffsetVar).getRawUValue());
+ llvm::erase(AbstractOriginVars, (*OffsetVar).getRawUValue());
} else if (ChildTag == dwarf::DW_TAG_lexical_block)
updateVarsWithAbstractOriginLocCovInfo(Child, AbstractOriginVars);
Child = Child.getSibling();
@@ -792,7 +792,7 @@
ProcessedFns.push_back(FnOffset);
}
for (auto ProcessedFn : ProcessedFns)
- llvm::erase_value(FnsWithAbstractOriginToBeProcessed, ProcessedFn);
+ llvm::erase(FnsWithAbstractOriginToBeProcessed, ProcessedFn);
}
/// Collect zero location coverage for inlined variables which refer to
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp b/src/llvm-project/llvm/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp
index 1d74856..0e74d0b 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp
@@ -20,8 +20,8 @@
using namespace object;
extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
- std::unique_ptr<MemoryBuffer> Buff = MemoryBuffer::getMemBuffer(
- StringRef((const char *)data, size), "", false);
+ std::string Payload(reinterpret_cast<const char *>(data), size);
+ std::unique_ptr<MemoryBuffer> Buff = MemoryBuffer::getMemBuffer(Payload);
Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
ObjectFile::createObjectFile(Buff->getMemBufferRef());
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/src/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 156e10c..941df4e 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -181,6 +181,13 @@
static opt<bool> IgnoreCase("ignore-case",
desc("Ignore case distinctions when using --name."),
value_desc("i"), cat(DwarfDumpCategory));
+static opt<bool> DumpNonSkeleton(
+ "dwo",
+ desc("Dump the non skeleton DIE in the .dwo or .dwp file after dumping the "
+ "skeleton DIE from the main executable. This allows dumping the .dwo "
+ "files with resolved addresses."),
+ value_desc("d"), cat(DwarfDumpCategory));
+
static alias IgnoreCaseAlias("i", desc("Alias for --ignore-case."),
aliasopt(IgnoreCase), cl::NotHidden);
static list<std::string> Name(
@@ -315,6 +322,7 @@
DumpOpts.ShowForm = ShowForm;
DumpOpts.SummarizeTypes = SummarizeTypes;
DumpOpts.Verbose = Verbose;
+ DumpOpts.DumpNonSkeleton = DumpNonSkeleton;
DumpOpts.RecoverableErrorHandler = C.getRecoverableErrorHandler();
// In -verify mode, print DIEs without children in error messages.
if (Verify) {
@@ -337,10 +345,10 @@
return true;
if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {
- for (auto Arch : ArchFilters) {
+ for (const StringRef Arch : ArchFilters) {
// Match architecture number.
unsigned Value;
- if (!StringRef(Arch).getAsInteger(0, Value))
+ if (!Arch.getAsInteger(0, Value))
if (Value == getCPUType(*MachO))
return true;
@@ -390,15 +398,27 @@
const StringSet<> &Names, DWARFContext::unit_iterator_range CUs,
raw_ostream &OS,
std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
- for (const auto &CU : CUs)
- for (const auto &Entry : CU->dies()) {
- DWARFDie Die = {CU.get(), &Entry};
+ auto filterDieNames = [&](DWARFUnit *Unit) {
+ for (const auto &Entry : Unit->dies()) {
+ DWARFDie Die = {Unit, &Entry};
if (const char *Name = Die.getName(DINameKind::ShortName))
if (filterByName(Names, Die, Name, OS, GetNameForDWARFReg))
continue;
if (const char *Name = Die.getName(DINameKind::LinkageName))
filterByName(Names, Die, Name, OS, GetNameForDWARFReg);
}
+ };
+ for (const auto &CU : CUs) {
+ filterDieNames(CU.get());
+ if (DumpNonSkeleton) {
+ // If we have split DWARF, then recurse down into the .dwo files as well.
+ DWARFDie CUDie = CU->getUnitDIE(false);
+ DWARFDie CUNonSkeletonDie = CU->getNonSkeletonUnitDIE(false);
+ // If we have a DWO file, we need to search it as well
+ if (CUNonSkeletonDie && CUDie != CUNonSkeletonDie)
+ filterDieNames(CUNonSkeletonDie.getDwarfUnit());
+ }
+ }
}
static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,
@@ -499,7 +519,7 @@
/// information or probably display all matched entries, or something else...
static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
raw_ostream &OS) {
- auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup);
+ auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup, DumpNonSkeleton);
if (!DIEsForAddr)
return false;
@@ -649,7 +669,7 @@
// Handle the --name option.
if (!Name.empty()) {
StringSet<> Names;
- for (auto name : Name)
+ for (const auto &name : Name)
Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);
filterByName(Names, DICtx.normal_units(), OS, GetRegName);
@@ -698,7 +718,7 @@
HandlerFn HandleObj, raw_ostream &OS) {
bool Result = true;
Error Err = Error::success();
- for (auto Child : Arch.children(Err)) {
+ for (const auto &Child : Arch.children(Err)) {
auto BuffOrErr = Child.getMemoryBufferRef();
error(Filename, BuffOrErr.takeError());
auto NameOrErr = Child.getName();
@@ -848,19 +868,19 @@
bool Success = true;
if (Verify) {
- for (auto Object : Objects)
+ for (StringRef Object : Objects)
Success &= handleFile(Object, verifyObjectFile, OutputFile.os());
} else if (Statistics) {
- for (auto Object : Objects)
+ for (StringRef Object : Objects)
Success &= handleFile(Object, collectStatsForObjectFile, OutputFile.os());
} else if (ShowSectionSizes) {
- for (auto Object : Objects)
+ for (StringRef Object : Objects)
Success &= handleFile(Object, collectObjectSectionSizes, OutputFile.os());
} else if (ShowSources) {
- for (auto Object : Objects)
+ for (StringRef Object : Objects)
Success &= handleFile(Object, collectObjectSources, OutputFile.os());
} else {
- for (auto Object : Objects)
+ for (StringRef Object : Objects)
Success &= handleFile(Object, dumpObjectFile, OutputFile.os());
}
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt
index b258579..23a5267 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt
@@ -8,6 +8,7 @@
AllTargetsInfos
CodeGenTypes
DWARFLinker
+ DWARFLinkerClassic
DWARFLinkerParallel
DebugInfoDWARF
MC
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index 47a23e8..bd17f3c 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -9,17 +9,18 @@
#include "DebugInfoLinker.h"
#include "Error.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/DWARFLinker/DWARFLinker.h"
-#include "llvm/DWARFLinker/DWARFStreamer.h"
-#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
+#include "llvm/DWARFLinker/Classic/DWARFLinker.h"
+#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
+#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Endian.h"
#include <memory>
#include <vector>
namespace llvm {
+using namespace dwarf_linker;
+
namespace dwarfutil {
// ObjFileAddressMap allows to check whether specified DIE referencing
@@ -38,8 +39,7 @@
// exec: [LowPC, HighPC] is not inside address ranges of .text sections
//
// universal: maxpc and bfd
-template <typename AddressMapBase>
-class ObjFileAddressMap : public AddressMapBase {
+class ObjFileAddressMap : public AddressesMap {
public:
ObjFileAddressMap(DWARFContext &Context, const Options &Options,
object::ObjectFile &ObjFile)
@@ -80,8 +80,8 @@
// should be renamed into has valid address ranges
bool hasValidRelocs() override { return HasValidAddressRanges; }
- std::optional<int64_t>
- getSubprogramRelocAdjustment(const DWARFDie &DIE) override {
+ std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,
+ bool Verbose) override {
assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
DIE.getTag() == dwarf::DW_TAG_label) &&
"Wrong type of input die");
@@ -98,15 +98,18 @@
return std::nullopt;
}
- std::optional<int64_t> getExprOpAddressRelocAdjustment(
- DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
- uint64_t EndOffset) override {
+ std::optional<int64_t>
+ getExprOpAddressRelocAdjustment(DWARFUnit &U,
+ const DWARFExpression::Operation &Op,
+ uint64_t, uint64_t, bool Verbose) override {
switch (Op.getCode()) {
default: {
assert(false && "Specified operation does not have address operand");
} break;
+ case dwarf::DW_OP_const2u:
case dwarf::DW_OP_const4u:
case dwarf::DW_OP_const8u:
+ case dwarf::DW_OP_const2s:
case dwarf::DW_OP_const4s:
case dwarf::DW_OP_const8s:
case dwarf::DW_OP_addr: {
@@ -130,11 +133,23 @@
return std::nullopt;
}
+ std::optional<StringRef> getLibraryInstallName() override {
+ return std::nullopt;
+ }
+
bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
// no need to apply relocations to the linked binary.
return false;
}
+ bool needToSaveValidRelocs() override { return false; }
+
+ void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
+ uint64_t) override {}
+
+ void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
+ uint64_t OutputUnitOffset) override {}
+
void clear() override {}
protected:
@@ -284,26 +299,36 @@
return Message;
}
-template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
+template <typename Linker>
Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
raw_pwrite_stream &OutStream) {
+ std::mutex ErrorHandlerMutex;
+
auto ReportWarn = [&](const Twine &Message, StringRef Context,
const DWARFDie *Die) {
- warning(Message, Context);
-
- if (!Options.Verbose || !Die)
+ // FIXME: implement warning logging which does not block other threads.
+ if (!ErrorHandlerMutex.try_lock())
return;
- DIDumpOptions DumpOpts;
- DumpOpts.ChildRecurseDepth = 0;
- DumpOpts.Verbose = Options.Verbose;
+ warning(Message, Context);
+ if (Options.Verbose && Die) {
+ DIDumpOptions DumpOpts;
+ DumpOpts.ChildRecurseDepth = 0;
+ DumpOpts.Verbose = Options.Verbose;
- WithColor::note() << " in DIE:\n";
- Die->dump(errs(), /*Indent=*/6, DumpOpts);
+ WithColor::note() << " in DIE:\n";
+ Die->dump(errs(), /*Indent=*/6, DumpOpts);
+ }
+ ErrorHandlerMutex.unlock();
};
auto ReportErr = [&](const Twine &Message, StringRef Context,
const DWARFDie *) {
+ // FIXME: implement error logging which does not block other threads.
+ if (!ErrorHandlerMutex.try_lock())
+ return;
+
WithColor::error(errs(), Context) << Message << '\n';
+ ErrorHandlerMutex.unlock();
};
// Create DWARF linker.
@@ -311,9 +336,26 @@
Linker::createLinker(ReportErr, ReportWarn);
Triple TargetTriple = File.makeTriple();
- if (Error Err = DebugInfoLinker->createEmitter(
- TargetTriple, Linker::OutputFileType::Object, OutStream))
- return Err;
+ std::unique_ptr<classic::DwarfStreamer> Streamer;
+ if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
+ classic::DwarfStreamer::createStreamer(
+ TargetTriple, Linker::OutputFileType::Object, OutStream, nullptr,
+ ReportWarn))
+ Streamer = std::move(*StreamerOrErr);
+ else
+ return StreamerOrErr.takeError();
+
+ if constexpr (std::is_same<Linker,
+ dwarf_linker::parallel::DWARFLinker>::value) {
+ DebugInfoLinker->setOutputDWARFHandler(
+ TargetTriple,
+ [&](std::shared_ptr<dwarf_linker::parallel::SectionDescriptorBase>
+ Section) {
+ Streamer->emitSectionContents(Section->getContents(),
+ Section->getKind());
+ });
+ } else
+ DebugInfoLinker->setOutputDWARFEmitter(Streamer.get());
DebugInfoLinker->setEstimatedObjfilesAmount(1);
DebugInfoLinker->setNumThreads(Options.NumThreads);
@@ -321,18 +363,26 @@
DebugInfoLinker->setVerbosity(Options.Verbose);
DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
- std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1);
- std::vector<std::string> EmptyWarnings;
+ std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
// Add object files to the DWARFLinker.
- std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
- std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap(
- std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options,
- File));
+ std::unique_ptr<DWARFContext> Context = DWARFContext::create(
+ File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
+ [&](Error Err) {
+ handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
+ ReportErr(Info.message(), "", nullptr);
+ });
+ },
+ [&](Error Warning) {
+ handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
+ ReportWarn(Info.message(), "", nullptr);
+ });
+ });
+ std::unique_ptr<ObjFileAddressMap> AddressesMap(
+ std::make_unique<ObjFileAddressMap>(*Context, Options, File));
- ObjectsForLinking[0] =
- std::make_unique<OutDwarfFile>(File.getFileName(), std::move(Context),
- std::move(AddressesMap), EmptyWarnings);
+ ObjectsForLinking[0] = std::make_unique<DWARFFile>(
+ File.getFileName(), std::move(Context), std::move(AddressesMap));
uint16_t MaxDWARFVersion = 0;
std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
@@ -367,7 +417,7 @@
for (typename Linker::AccelTableKind Table : AccelTables)
DebugInfoLinker->addAccelTableKind(Table);
- for (std::unique_ptr<OutDwarfFile> &CurFile : ObjectsForLinking) {
+ for (std::unique_ptr<DWARFFile> &CurFile : ObjectsForLinking) {
SmallVector<StringRef> AccelTableNamesToReplace;
SmallVector<StringRef> AccelTableNamesToDelete;
@@ -412,20 +462,16 @@
if (Error Err = DebugInfoLinker->link())
return Err;
- DebugInfoLinker->getEmitter()->finish();
+ Streamer->finish();
return Error::success();
}
Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
raw_pwrite_stream &OutStream) {
- if (Options.UseLLVMDWARFLinker)
- return linkDebugInfoImpl<dwarflinker_parallel::DWARFLinker,
- dwarflinker_parallel::DWARFFile,
- dwarflinker_parallel::AddressesMap>(File, Options,
- OutStream);
+ if (Options.UseDWARFLinkerParallel)
+ return linkDebugInfoImpl<parallel::DWARFLinker>(File, Options, OutStream);
else
- return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>(
- File, Options, OutStream);
+ return linkDebugInfoImpl<classic::DWARFLinker>(File, Options, OutStream);
}
} // end of namespace dwarfutil
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h b/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
index d9d99ff..77cb8bb 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
@@ -18,7 +18,7 @@
namespace dwarfutil {
inline bool isDebugSection(StringRef SecName) {
- return SecName.startswith(".debug") || SecName.startswith(".zdebug") ||
+ return SecName.starts_with(".debug") || SecName.starts_with(".zdebug") ||
SecName == ".gdb_index";
}
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/Error.h b/src/llvm-project/llvm/tools/llvm-dwarfutil/Error.h
index b92c50c..fff5978 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/Error.h
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/Error.h
@@ -11,7 +11,6 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h
index e97833b..e3cfa42 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h
@@ -9,8 +9,8 @@
#ifndef LLVM_TOOLS_LLVM_DWARFUTIL_OPTIONS_H
#define LLVM_TOOLS_LLVM_DWARFUTIL_OPTIONS_H
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
namespace llvm {
namespace dwarfutil {
@@ -40,7 +40,7 @@
bool Verbose = false;
int NumThreads = 0;
bool Verify = false;
- bool UseLLVMDWARFLinker = false;
+ bool UseDWARFLinkerParallel = false;
DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None;
std::string getSeparateDebugFileName() const {
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td
index 26b9ac6..85606bd 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td
@@ -22,7 +22,7 @@
def linker: Separate<["--", "-"], "linker">,
MetaVarName<"<DWARF linker type>">,
- HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">;
+ HelpText<"Specify the desired type of DWARF linker. Defaults to 'classic'">;
def: Joined<["--", "-"], "linker=">, Alias<linker>;
defm odr_deduplication : BB<"odr-deduplication",
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/src/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index 1c76271..7b777b1 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -33,9 +33,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Options.inc"
#undef OPTION
};
@@ -47,14 +45,9 @@
#include "Options.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Options.inc"
#undef OPTION
};
@@ -125,10 +118,10 @@
if (opt::Arg *LinkerKind = Args.getLastArg(OPT_linker)) {
StringRef S = LinkerKind->getValue();
- if (S == "apple")
- Options.UseLLVMDWARFLinker = false;
- else if (S == "llvm")
- Options.UseLLVMDWARFLinker = true;
+ if (S == "classic")
+ Options.UseDWARFLinkerParallel = false;
+ else if (S == "parallel")
+ Options.UseDWARFLinkerParallel = true;
else
return createStringError(
std::errc::invalid_argument,
diff --git a/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt
index e27c0c3..d38385c 100644
--- a/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt
@@ -21,6 +21,7 @@
DEPENDS
intrinsics_gen
DwpOptsTableGen
+ GENERATE_DRIVER
)
if(LLVM_INSTALL_BINUTILS_SYMLINKS)
diff --git a/src/llvm-project/llvm/tools/llvm-dwp/Opts.td b/src/llvm-project/llvm/tools/llvm-dwp/Opts.td
index c01fa4a..46593bc 100644
--- a/src/llvm-project/llvm/tools/llvm-dwp/Opts.td
+++ b/src/llvm-project/llvm/tools/llvm-dwp/Opts.td
@@ -9,5 +9,10 @@
def execFileNames : S<"e", "Specify the executable/library files to get the list of *.dwo from.">, MetaVarName<"<filename>">;
def outputFileName : S<"o", "Specify the output file.">, MetaVarName<"<filename>">;
-def continueOnCuIndexOverflow: F<"continue-on-cu-index-overflow", "This turns an error when offset for .debug_*.dwo sections "
- "overfolws into a warning.">, MetaVarName<"<filename>">;
+def continueOnCuIndexOverflow : Flag<["-", "--"], "continue-on-cu-index-overflow">;
+def continueOnCuIndexOverflow_EQ : Joined<["-", "--"], "continue-on-cu-index-overflow=">,
+ HelpText<"default = continue, This turns an error when offset \n"
+ "\t\tfor .debug_*.dwo sections overfolws into a warning. = soft-stop, This produces a \n"
+ "\t\ttruncated but valid DWP file, discarding any DWO files that would not fit within \n"
+ "\t\tthe 32 bit/4GB limits of the format.">,
+ Values<"continue,soft-stop">;
diff --git a/src/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp b/src/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp
index 350a373..81556b3 100644
--- a/src/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp
@@ -27,7 +27,7 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
@@ -42,9 +42,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -56,14 +54,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -77,7 +70,7 @@
// Options
static std::vector<std::string> ExecFilenames;
static std::string OutputFilename;
-static bool ContinueOnCuIndexOverflow;
+static std::string ContinueOption;
static Expected<SmallVector<std::string, 16>>
getDWOFilenames(StringRef ExecFilename) {
@@ -125,12 +118,11 @@
return ErrOrObj->getBinary()->makeTriple();
}
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
-
+int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
DwpOptTable Tbl;
llvm::BumpPtrAllocator A;
llvm::StringSaver Saver{A};
+ OnCuIndexOverflow OverflowOptValue = OnCuIndexOverflow::HardStop;
opt::InputArgList Args =
Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
llvm::errs() << Msg << '\n';
@@ -149,7 +141,23 @@
}
OutputFilename = Args.getLastArgValue(OPT_outputFileName, "");
- ContinueOnCuIndexOverflow = Args.hasArg(OPT_continueOnCuIndexOverflow);
+ if (Arg *Arg = Args.getLastArg(OPT_continueOnCuIndexOverflow,
+ OPT_continueOnCuIndexOverflow_EQ)) {
+ if (Arg->getOption().matches(OPT_continueOnCuIndexOverflow)) {
+ OverflowOptValue = OnCuIndexOverflow::Continue;
+ } else {
+ ContinueOption = Arg->getValue();
+ if (ContinueOption == "soft-stop") {
+ OverflowOptValue = OnCuIndexOverflow::SoftStop;
+ } else if (ContinueOption == "continue") {
+ OverflowOptValue = OnCuIndexOverflow::Continue;
+ } else {
+ llvm::errs() << "invalid value for --continue-on-cu-index-overflow"
+ << ContinueOption << '\n';
+ exit(1);
+ }
+ }
+ }
for (const llvm::opt::Arg *A : Args.filtered(OPT_execFileNames))
ExecFilenames.emplace_back(A->getValue());
@@ -261,7 +269,7 @@
if (!MS)
return error("no object streamer for target " + TripleName, Context);
- if (auto Err = write(*MS, DWOFilenames, ContinueOnCuIndexOverflow)) {
+ if (auto Err = write(*MS, DWOFilenames, OverflowOptValue)) {
logAllUnhandledErrors(std::move(Err), WithColor::error());
return 1;
}
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
index c778b89..5184686 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
@@ -9,6 +9,9 @@
#include "AArch64.h"
#include "AArch64RegisterInfo.h"
+#define GET_AVAILABLE_OPCODE_CHECKER
+#include "AArch64GenInstrInfo.inc"
+
namespace llvm {
namespace exegesis {
@@ -38,7 +41,8 @@
class ExegesisAArch64Target : public ExegesisTarget {
public:
- ExegesisAArch64Target() : ExegesisTarget(AArch64CpuPfmCounters) {}
+ ExegesisAArch64Target()
+ : ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
private:
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp
index 7c44373..2b924b9 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp
@@ -13,7 +13,6 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Support/FormatVariadic.h"
#include <limits>
-#include <unordered_set>
#include <vector>
namespace llvm {
@@ -390,7 +389,7 @@
OS << "<li><span class=\"mono\">";
writeEscaped<kEscapeHtml>(OS,
SM.getProcResource(WPR.ProcResourceIdx)->Name);
- OS << "</span>: " << WPR.Cycles << "</li>";
+ OS << "</span>: " << WPR.ReleaseAtCycle << "</li>";
}
OS << "</ul></td>";
// Idealized port pressure.
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.h
index 9970cfe..4a85d45 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.h
@@ -23,9 +23,6 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
-#include <set>
-#include <string>
-#include <unordered_map>
namespace llvm {
namespace exegesis {
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.cpp
index 97b461e..9f03a4e 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.cpp
@@ -19,13 +19,15 @@
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
-#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/Object/SymbolSize.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,6 +36,10 @@
#include "perfmon/perf_event.h"
#endif // HAVE_LIBPFM
+#ifdef __linux__
+#include <unistd.h>
+#endif
+
namespace llvm {
namespace exegesis {
@@ -43,14 +49,22 @@
// Fills the given basic block with register setup code, and returns true if
// all registers could be setup correctly.
-static bool generateSnippetSetupCode(
- const ExegesisTarget &ET, const MCSubtargetInfo *const MSI,
- ArrayRef<RegisterValue> RegisterInitialValues, BasicBlockFiller &BBF,
- const BenchmarkKey &Key, bool GenerateMemoryInstructions) {
+static bool generateSnippetSetupCode(const ExegesisTarget &ET,
+ const MCSubtargetInfo *const MSI,
+ BasicBlockFiller &BBF,
+ const BenchmarkKey &Key,
+ bool GenerateMemoryInstructions) {
bool IsSnippetSetupComplete = true;
if (GenerateMemoryInstructions) {
BBF.addInstructions(ET.generateMemoryInitialSetup());
for (const MemoryMapping &MM : Key.MemoryMappings) {
+#ifdef __linux__
+ // The frontend that generates that parses the memory mapping information
+ // from the user should validate that the requested address is a multiple
+ // of the page size. Assert that this is true here.
+ assert(MM.Address % getpagesize() == 0 &&
+ "Memory mappings need to be aligned to page boundaries.");
+#endif
BBF.addInstructions(ET.generateMmap(
MM.Address, Key.MemoryValues.at(MM.MemoryValueName).SizeBytes,
ET.getAuxiliaryMemoryStartAddress() +
@@ -59,7 +73,17 @@
}
BBF.addInstructions(ET.setStackRegisterToAuxMem());
}
- for (const RegisterValue &RV : RegisterInitialValues) {
+ Register StackPointerRegister = BBF.MF.getSubtarget()
+ .getTargetLowering()
+ ->getStackPointerRegisterToSaveRestore();
+ for (const RegisterValue &RV : Key.RegisterInitialValues) {
+ if (GenerateMemoryInstructions) {
+ // If we're generating memory instructions, don't load in the value for
+ // the register with the stack pointer as it will be used later to finish
+ // the setup.
+ if (RV.Register == StackPointerRegister)
+ continue;
+ }
// Load a constant in the register.
const auto SetRegisterCode = ET.setRegTo(*MSI, RV.Register, RV.Value);
if (SetRegisterCode.empty())
@@ -70,6 +94,18 @@
#ifdef HAVE_LIBPFM
BBF.addInstructions(ET.configurePerfCounter(PERF_EVENT_IOC_RESET, true));
#endif // HAVE_LIBPFM
+ for (const RegisterValue &RV : Key.RegisterInitialValues) {
+ // Load in the stack register now as we're done using it elsewhere
+ // and need to set the value in preparation for executing the
+ // snippet.
+ if (RV.Register != StackPointerRegister)
+ continue;
+ const auto SetRegisterCode = ET.setRegTo(*MSI, RV.Register, RV.Value);
+ if (SetRegisterCode.empty())
+ IsSnippetSetupComplete = false;
+ BBF.addInstructions(SetRegisterCode);
+ break;
+ }
}
return IsSnippetSetupComplete;
}
@@ -105,7 +141,7 @@
FunctionType *FunctionType =
FunctionType::get(ReturnType, {MemParamType}, false);
Function *const F = Function::Create(
- FunctionType, GlobalValue::InternalLinkage, FunctionName, Module);
+ FunctionType, GlobalValue::ExternalLinkage, FunctionName, Module);
BasicBlock *BB = BasicBlock::Create(Module->getContext(), "", F);
new UnreachableInst(Module->getContext(), BB);
return MMI->getOrCreateMachineFunction(*F);
@@ -207,10 +243,8 @@
Error assembleToStream(const ExegesisTarget &ET,
std::unique_ptr<LLVMTargetMachine> TM,
- ArrayRef<unsigned> LiveIns,
- ArrayRef<RegisterValue> RegisterInitialValues,
- const FillFunction &Fill, raw_pwrite_stream &AsmStream,
- const BenchmarkKey &Key,
+ ArrayRef<unsigned> LiveIns, const FillFunction &Fill,
+ raw_pwrite_stream &AsmStream, const BenchmarkKey &Key,
bool GenerateMemoryInstructions) {
auto Context = std::make_unique<LLVMContext>();
std::unique_ptr<Module> Module =
@@ -240,7 +274,7 @@
}
std::vector<unsigned> RegistersSetUp;
- for (const auto &InitValue : RegisterInitialValues) {
+ for (const auto &InitValue : Key.RegisterInitialValues) {
RegistersSetUp.push_back(InitValue.Register);
}
FunctionFiller Sink(MF, std::move(RegistersSetUp));
@@ -259,8 +293,7 @@
}
const bool IsSnippetSetupComplete = generateSnippetSetupCode(
- ET, TM->getMCSubtargetInfo(), RegisterInitialValues, Entry, Key,
- GenerateMemoryInstructions);
+ ET, TM->getMCSubtargetInfo(), Entry, Key, GenerateMemoryInstructions);
// If the snippet setup is not complete, we disable liveliness tracking. This
// means that we won't know what values are in the registers.
@@ -299,7 +332,8 @@
TPC->setInitialized();
// AsmPrinter is responsible for generating the assembly into AsmBuffer.
- if (TM->addAsmPrinter(PM, AsmStream, nullptr, CGFT_ObjectFile, MCContext))
+ if (TM->addAsmPrinter(PM, AsmStream, nullptr, CodeGenFileType::ObjectFile,
+ MCContext))
return make_error<Failure>("Cannot add AsmPrinter passes");
PM.run(*Module); // Run all the passes
@@ -323,61 +357,49 @@
return cantFail(object::ObjectFile::createObjectFile(Filename));
}
-namespace {
-
-// Implementation of this class relies on the fact that a single object with a
-// single function will be loaded into memory.
-class TrackingSectionMemoryManager : public SectionMemoryManager {
-public:
- explicit TrackingSectionMemoryManager(uintptr_t *CodeSize)
- : CodeSize(CodeSize) {}
-
- uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID,
- StringRef SectionName) override {
- *CodeSize = Size;
- return SectionMemoryManager::allocateCodeSection(Size, Alignment, SectionID,
- SectionName);
- }
-
-private:
- uintptr_t *const CodeSize = nullptr;
-};
-
-} // namespace
-
-ExecutableFunction::ExecutableFunction(
+Expected<ExecutableFunction> ExecutableFunction::create(
std::unique_ptr<LLVMTargetMachine> TM,
- object::OwningBinary<object::ObjectFile> &&ObjectFileHolder)
- : Context(std::make_unique<LLVMContext>()) {
+ object::OwningBinary<object::ObjectFile> &&ObjectFileHolder) {
assert(ObjectFileHolder.getBinary() && "cannot create object file");
- // Initializing the execution engine.
- // We need to use the JIT EngineKind to be able to add an object file.
- LLVMLinkInMCJIT();
- uintptr_t CodeSize = 0;
- std::string Error;
- ExecEngine.reset(
- EngineBuilder(createModule(Context, TM->createDataLayout()))
- .setErrorStr(&Error)
- .setMCPU(TM->getTargetCPU())
- .setEngineKind(EngineKind::JIT)
- .setMCJITMemoryManager(
- std::make_unique<TrackingSectionMemoryManager>(&CodeSize))
- .create(TM.release()));
- if (!ExecEngine)
- report_fatal_error(Twine(Error));
- // Adding the generated object file containing the assembled function.
- // The ExecutionEngine makes sure the object file is copied into an
- // executable page.
- ExecEngine->addObjectFile(std::move(ObjectFileHolder));
- // Fetching function bytes.
- const uint64_t FunctionAddress = ExecEngine->getFunctionAddress(FunctionID);
+ std::unique_ptr<LLVMContext> Ctx = std::make_unique<LLVMContext>();
+
+ auto SymbolSizes = object::computeSymbolSizes(*ObjectFileHolder.getBinary());
+ // Get the size of the function that we want to call into (with the name of
+ // FunctionID). This should always be the third symbol returned by
+ // calculateSymbolSizes.
+ assert(SymbolSizes.size() == 3);
+ assert(cantFail(std::get<0>(SymbolSizes[2]).getName()) == FunctionID);
+ uintptr_t CodeSize = std::get<1>(SymbolSizes[2]);
+
+ auto EJITOrErr = orc::LLJITBuilder().create();
+ if (!EJITOrErr)
+ return EJITOrErr.takeError();
+
+ auto EJIT = std::move(*EJITOrErr);
+
+ if (auto ObjErr =
+ EJIT->addObjectFile(std::get<1>(ObjectFileHolder.takeBinary())))
+ return std::move(ObjErr);
+
+ auto FunctionAddressOrErr = EJIT->lookup(FunctionID);
+ if (!FunctionAddressOrErr)
+ return FunctionAddressOrErr.takeError();
+
+ const uint64_t FunctionAddress = FunctionAddressOrErr->getValue();
+
assert(isAligned(kFunctionAlignment, FunctionAddress) &&
"function is not properly aligned");
- FunctionBytes =
+
+ StringRef FBytes =
StringRef(reinterpret_cast<const char *>(FunctionAddress), CodeSize);
+ return ExecutableFunction(std::move(Ctx), std::move(EJIT), FBytes);
}
+ExecutableFunction::ExecutableFunction(std::unique_ptr<LLVMContext> Ctx,
+ std::unique_ptr<orc::LLJIT> EJIT,
+ StringRef FB)
+ : FunctionBytes(FB), Context(std::move(Ctx)), ExecJIT(std::move(EJIT)) {}
+
Error getBenchmarkFunctionBytes(const StringRef InputData,
std::vector<uint8_t> &Bytes) {
const auto Holder = getObjectFromBuffer(InputData);
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.h
index 7c2a002..d85d7fd 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.h
@@ -23,7 +23,7 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCInst.h"
@@ -90,10 +90,8 @@
// AsmStream, the temporary function is eventually discarded.
Error assembleToStream(const ExegesisTarget &ET,
std::unique_ptr<LLVMTargetMachine> TM,
- ArrayRef<unsigned> LiveIns,
- ArrayRef<RegisterValue> RegisterInitialValues,
- const FillFunction &Fill, raw_pwrite_stream &AsmStreamm,
- const BenchmarkKey &Key,
+ ArrayRef<unsigned> LiveIns, const FillFunction &Fill,
+ raw_pwrite_stream &AsmStreamm, const BenchmarkKey &Key,
bool GenerateMemoryInstructions);
// Creates an ObjectFile in the format understood by the host.
@@ -106,10 +104,11 @@
// Consumes an ObjectFile containing a `void foo(char*)` function and make it
// executable.
-struct ExecutableFunction {
- explicit ExecutableFunction(
- std::unique_ptr<LLVMTargetMachine> TM,
- object::OwningBinary<object::ObjectFile> &&ObjectFileHolder);
+class ExecutableFunction {
+public:
+ static Expected<ExecutableFunction>
+ create(std::unique_ptr<LLVMTargetMachine> TM,
+ object::OwningBinary<object::ObjectFile> &&ObjectFileHolder);
// Retrieves the function as an array of bytes.
StringRef getFunctionBytes() const { return FunctionBytes; }
@@ -119,9 +118,14 @@
((void (*)(char *))(intptr_t)FunctionBytes.data())(Memory);
}
- std::unique_ptr<LLVMContext> Context;
- std::unique_ptr<ExecutionEngine> ExecEngine;
StringRef FunctionBytes;
+
+private:
+ ExecutableFunction(std::unique_ptr<LLVMContext> Ctx,
+ std::unique_ptr<orc::LLJIT> EJIT, StringRef FunctionBytes);
+
+ std::unique_ptr<LLVMContext> Context;
+ std::unique_ptr<orc::LLJIT> ExecJIT;
};
// Copies benchmark function's bytes from benchmark object.
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index b8e53de..e985c32 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -11,10 +11,10 @@
#include "Error.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/bit.h"
#include "llvm/ObjectYAML/YAML.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -193,6 +193,66 @@
static const bool flow = false;
};
+const char *validationEventToString(exegesis::ValidationEvent VE) {
+ switch (VE) {
+ case exegesis::ValidationEvent::InstructionRetired:
+ return "instructions-retired";
+ case exegesis::ValidationEvent::L1DCacheLoadMiss:
+ return "l1d-cache-load-misses";
+ case exegesis::ValidationEvent::L1DCacheStoreMiss:
+ return "l1d-cache-store-misses";
+ case exegesis::ValidationEvent::L1ICacheLoadMiss:
+ return "l1i-cache-load-misses";
+ case exegesis::ValidationEvent::DataTLBLoadMiss:
+ return "data-tlb-load-misses";
+ case exegesis::ValidationEvent::DataTLBStoreMiss:
+ return "data-tlb-store-misses";
+ case exegesis::ValidationEvent::InstructionTLBLoadMiss:
+ return "instruction-tlb-load-misses";
+ }
+ llvm_unreachable("Unhandled exegesis::ValidationEvent enum");
+}
+
+Expected<exegesis::ValidationEvent> stringToValidationEvent(StringRef Input) {
+ if (Input == "instructions-retired")
+ return exegesis::ValidationEvent::InstructionRetired;
+ else if (Input == "l1d-cache-load-misses")
+ return exegesis::ValidationEvent::L1DCacheLoadMiss;
+ else if (Input == "l1d-cache-store-misses")
+ return exegesis::ValidationEvent::L1DCacheStoreMiss;
+ else if (Input == "l1i-cache-load-misses")
+ return exegesis::ValidationEvent::L1ICacheLoadMiss;
+ else if (Input == "data-tlb-load-misses")
+ return exegesis::ValidationEvent::DataTLBLoadMiss;
+ else if (Input == "data-tlb-store-misses")
+ return exegesis::ValidationEvent::DataTLBStoreMiss;
+ else if (Input == "instruction-tlb-load-misses")
+ return exegesis::ValidationEvent::InstructionTLBLoadMiss;
+ else
+ return make_error<StringError>("Invalid validation event string",
+ errc::invalid_argument);
+}
+
+template <>
+struct CustomMappingTraits<std::map<exegesis::ValidationEvent, int64_t>> {
+ static void inputOne(IO &Io, StringRef KeyStr,
+ std::map<exegesis::ValidationEvent, int64_t> &VI) {
+ Expected<exegesis::ValidationEvent> Key = stringToValidationEvent(KeyStr);
+ if (!Key) {
+ Io.setError("Key is not a valid validation event");
+ return;
+ }
+ Io.mapRequired(KeyStr.str().c_str(), VI[*Key]);
+ }
+
+ static void output(IO &Io, std::map<exegesis::ValidationEvent, int64_t> &VI) {
+ for (auto &IndividualVI : VI) {
+ Io.mapRequired(validationEventToString(IndividualVI.first),
+ IndividualVI.second);
+ }
+ }
+};
+
// exegesis::Measure is rendererd as a flow instead of a list.
// e.g. { "key": "the key", "value": 0123 }
template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
@@ -204,6 +264,7 @@
}
Io.mapRequired("value", Obj.PerInstructionValue);
Io.mapOptional("per_snippet_value", Obj.PerSnippetValue);
+ Io.mapOptional("validation_counters", Obj.ValidationCounters);
}
static const bool flow = true;
};
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
index 77e0994..7769c9d 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -17,9 +17,7 @@
#include "LlvmState.h"
#include "RegisterValue.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/Support/YAMLTraits.h"
@@ -34,6 +32,16 @@
namespace exegesis {
+enum ValidationEvent {
+ InstructionRetired,
+ L1DCacheLoadMiss,
+ L1DCacheStoreMiss,
+ L1ICacheLoadMiss,
+ DataTLBLoadMiss,
+ DataTLBStoreMiss,
+ InstructionTLBLoadMiss
+};
+
enum class BenchmarkPhaseSelectorE {
PrepareSnippet,
PrepareAndAssembleSnippet,
@@ -72,12 +80,17 @@
// An opaque configuration, that can be used to separate several benchmarks of
// the same instruction under different configurations.
std::string Config;
+ // The address that the snippet should be loaded in at if the execution mode
+ // being used supports it.
+ intptr_t SnippetAddress = 0;
};
struct BenchmarkMeasure {
// A helper to create an unscaled BenchmarkMeasure.
- static BenchmarkMeasure Create(std::string Key, double Value) {
- return {Key, Value, Value};
+ static BenchmarkMeasure
+ Create(std::string Key, double Value,
+ std::map<ValidationEvent, int64_t> ValCounters) {
+ return {Key, Value, Value, ValCounters};
}
std::string Key;
// This is the per-instruction value, i.e. measured quantity scaled per
@@ -86,6 +99,8 @@
// This is the per-snippet value, i.e. measured quantity for one repetition of
// the whole snippet.
double PerSnippetValue;
+ // These are the validation counter values.
+ std::map<ValidationEvent, int64_t> ValidationCounters;
};
// The result of an instruction benchmark.
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 96ac1ae..2b51228 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include <array>
+#include <cmath>
#include <memory>
#include <string>
@@ -14,10 +14,10 @@
#include "BenchmarkRunner.h"
#include "Error.h"
#include "MCInstrDescView.h"
+#include "MmapUtils.h"
#include "PerfHelper.h"
#include "SubprocessMemory.h"
#include "Target.h"
-#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -27,6 +27,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#ifdef __linux__
#ifdef HAVE_LIBPFM
@@ -34,6 +35,7 @@
#endif
#include <sys/mman.h>
#include <sys/ptrace.h>
+#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/wait.h>
@@ -45,16 +47,18 @@
#define GLIBC_INITS_RSEQ
#endif
#endif
-#endif
+#endif // __linux__
namespace llvm {
namespace exegesis {
BenchmarkRunner::BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- ExecutionModeE ExecutionMode)
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters)
: State(State), Mode(Mode), BenchmarkPhaseSelector(BenchmarkPhaseSelector),
- ExecutionMode(ExecutionMode), Scratch(std::make_unique<ScratchSpace>()) {}
+ ExecutionMode(ExecutionMode), ValidationCounters(ValCounters),
+ Scratch(std::make_unique<ScratchSpace>()) {}
BenchmarkRunner::~BenchmarkRunner() = default;
@@ -69,7 +73,9 @@
}
Expected<llvm::SmallVector<int64_t, 4>>
-BenchmarkRunner::FunctionExecutor::runAndSample(const char *Counters) const {
+BenchmarkRunner::FunctionExecutor::runAndSample(
+ const char *Counters, ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const {
// We sum counts when there are several counters for a single ProcRes
// (e.g. P23 on SandyBridge).
llvm::SmallVector<int64_t, 4> CounterValues;
@@ -77,8 +83,8 @@
StringRef(Counters).split(CounterNames, '+');
for (auto &CounterName : CounterNames) {
CounterName = CounterName.trim();
- Expected<SmallVector<int64_t, 4>> ValueOrError =
- runWithCounter(CounterName);
+ Expected<SmallVector<int64_t, 4>> ValueOrError = runWithCounter(
+ CounterName, ValidationCounters, ValidationCounterValues);
if (!ValueOrError)
return ValueOrError.takeError();
accumulateCounterValues(ValueOrError.get(), &CounterValues);
@@ -89,13 +95,25 @@
namespace {
class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
public:
- InProcessFunctionExecutorImpl(const LLVMState &State,
- object::OwningBinary<object::ObjectFile> Obj,
- BenchmarkRunner::ScratchSpace *Scratch)
- : State(State), Function(State.createTargetMachine(), std::move(Obj)),
- Scratch(Scratch) {}
+ static Expected<std::unique_ptr<InProcessFunctionExecutorImpl>>
+ create(const LLVMState &State, object::OwningBinary<object::ObjectFile> Obj,
+ BenchmarkRunner::ScratchSpace *Scratch) {
+ Expected<ExecutableFunction> EF =
+ ExecutableFunction::create(State.createTargetMachine(), std::move(Obj));
+
+ if (!EF)
+ return EF.takeError();
+
+ return std::unique_ptr<InProcessFunctionExecutorImpl>(
+ new InProcessFunctionExecutorImpl(State, std::move(*EF), Scratch));
+ }
private:
+ InProcessFunctionExecutorImpl(const LLVMState &State,
+ ExecutableFunction Function,
+ BenchmarkRunner::ScratchSpace *Scratch)
+ : State(State), Function(std::move(Function)), Scratch(Scratch) {}
+
static void
accumulateCounterValues(const llvm::SmallVector<int64_t, 4> &NewValues,
llvm::SmallVector<int64_t, 4> *Result) {
@@ -106,16 +124,18 @@
(*Result)[I] += NewValues[I];
}
- Expected<llvm::SmallVector<int64_t, 4>>
- runWithCounter(StringRef CounterName) const override {
+ Expected<llvm::SmallVector<int64_t, 4>> runWithCounter(
+ StringRef CounterName, ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const override {
const ExegesisTarget &ET = State.getExegesisTarget();
char *const ScratchPtr = Scratch->ptr();
- auto CounterOrError = ET.createCounter(CounterName, State);
+ auto CounterOrError =
+ ET.createCounter(CounterName, State, ValidationCounters);
if (!CounterOrError)
return CounterOrError.takeError();
- pfm::Counter *Counter = CounterOrError.get().get();
+ pfm::CounterGroup *Counter = CounterOrError.get().get();
Scratch->clear();
{
auto PS = ET.withSavedState();
@@ -129,20 +149,27 @@
CrashRecoveryContext::Disable();
PS.reset();
if (Crashed) {
- std::string Msg = "snippet crashed while running";
#ifdef LLVM_ON_UNIX
// See "Exit Status for Commands":
// https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
constexpr const int kSigOffset = 128;
- if (const char *const SigName = strsignal(CRC.RetCode - kSigOffset)) {
- Msg += ": ";
- Msg += SigName;
- }
-#endif
- return make_error<SnippetCrash>(std::move(Msg));
+ return make_error<SnippetSignal>(CRC.RetCode - kSigOffset);
+#else
+ // The exit code of the process on windows is not meaningful as a
+ // signal, so simply pass in -1 as the signal into the error.
+ return make_error<SnippetSignal>(-1);
+#endif // LLVM_ON_UNIX
}
}
+ auto ValidationValuesOrErr = Counter->readValidationCountersOrError();
+ if (!ValidationValuesOrErr)
+ return ValidationValuesOrErr.takeError();
+
+ ArrayRef RealValidationValues = *ValidationValuesOrErr;
+ for (size_t I = 0; I < RealValidationValues.size(); ++I)
+ ValidationCounterValues[I] = RealValidationValues[I];
+
return Counter->readOrError(Function.getFunctionBytes());
}
@@ -161,13 +188,24 @@
class SubProcessFunctionExecutorImpl
: public BenchmarkRunner::FunctionExecutor {
public:
- SubProcessFunctionExecutorImpl(const LLVMState &State,
- object::OwningBinary<object::ObjectFile> Obj,
- const BenchmarkKey &Key)
- : State(State), Function(State.createTargetMachine(), std::move(Obj)),
- Key(Key) {}
+ static Expected<std::unique_ptr<SubProcessFunctionExecutorImpl>>
+ create(const LLVMState &State, object::OwningBinary<object::ObjectFile> Obj,
+ const BenchmarkKey &Key) {
+ Expected<ExecutableFunction> EF =
+ ExecutableFunction::create(State.createTargetMachine(), std::move(Obj));
+ if (!EF)
+ return EF.takeError();
+
+ return std::unique_ptr<SubProcessFunctionExecutorImpl>(
+ new SubProcessFunctionExecutorImpl(State, std::move(*EF), Key));
+ }
private:
+ SubProcessFunctionExecutorImpl(const LLVMState &State,
+ ExecutableFunction Function,
+ const BenchmarkKey &Key)
+ : State(State), Function(std::move(Function)), Key(Key) {}
+
enum ChildProcessExitCodeE {
CounterFDReadFailed = 1,
RSeqDisableFailed,
@@ -209,7 +247,8 @@
ssize_t BytesWritten = sendmsg(SocketFD, &Message, 0);
if (BytesWritten < 0)
- return make_error<Failure>("Failed to write FD to socket");
+ return make_error<Failure>("Failed to write FD to socket: " +
+ Twine(strerror(errno)));
return Error::success();
}
@@ -221,10 +260,11 @@
Message.msg_control = ControlBuffer;
Message.msg_controllen = sizeof(ControlBuffer);
- size_t BytesRead = recvmsg(SocketFD, &Message, 0);
+ ssize_t BytesRead = recvmsg(SocketFD, &Message, 0);
if (BytesRead < 0)
- return make_error<Failure>("Failed to read FD from socket");
+ return make_error<Failure>("Failed to read FD from socket: " +
+ Twine(strerror(errno)));
struct cmsghdr *ControlMessage = CMSG_FIRSTHDR(&Message);
@@ -240,13 +280,16 @@
}
Error createSubProcessAndRunBenchmark(
- StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues) const {
+ StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues,
+ ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const {
int PipeFiles[2];
int PipeSuccessOrErr = socketpair(AF_UNIX, SOCK_DGRAM, 0, PipeFiles);
if (PipeSuccessOrErr != 0) {
return make_error<Failure>(
"Failed to create a pipe for interprocess communication between "
- "llvm-exegesis and the benchmarking subprocess");
+ "llvm-exegesis and the benchmarking subprocess: " +
+ Twine(strerror(errno)));
}
SubprocessMemory SPMemory;
@@ -260,6 +303,12 @@
return AddMemDefError;
pid_t ParentOrChildPID = fork();
+
+ if (ParentOrChildPID == -1) {
+ return make_error<Failure>("Failed to create child process: " +
+ Twine(strerror(errno)));
+ }
+
if (ParentOrChildPID == 0) {
// We are in the child process, close the write end of the pipe
close(PipeFiles[1]);
@@ -273,23 +322,23 @@
}
const ExegesisTarget &ET = State.getExegesisTarget();
- auto CounterOrError =
- ET.createCounter(CounterName, State, ParentOrChildPID);
+ auto CounterOrError = ET.createCounter(
+ CounterName, State, ValidationCounters, ParentOrChildPID);
if (!CounterOrError)
return CounterOrError.takeError();
- pfm::Counter *Counter = CounterOrError.get().get();
+ pfm::CounterGroup *Counter = CounterOrError.get().get();
close(PipeFiles[0]);
- int CounterFileDescriptor = Counter->getFileDescriptor();
- Error SendError =
- sendFileDescriptorThroughSocket(PipeFiles[1], CounterFileDescriptor);
-
- if (SendError)
- return SendError;
-
+ // Make sure to attach to the process (and wait for the sigstop to be
+ // delivered and for the process to continue) before we write to the counter
+ // file descriptor. Attaching to the process before writing to the socket
+ // ensures that the subprocess at most has blocked on the read call. If we
+ // attach afterwards, the subprocess might exit before we get to the attach
+ // call due to effects like scheduler contention, introducing transient
+ // failures.
if (ptrace(PTRACE_ATTACH, ParentOrChildPID, NULL, NULL) != 0)
return make_error<Failure>("Failed to attach to the child process: " +
Twine(strerror(errno)));
@@ -305,6 +354,13 @@
"Failed to continue execution of the child process: " +
Twine(strerror(errno)));
+ int CounterFileDescriptor = Counter->getFileDescriptor();
+ Error SendError =
+ sendFileDescriptorThroughSocket(PipeFiles[1], CounterFileDescriptor);
+
+ if (SendError)
+ return SendError;
+
int ChildStatus;
if (wait(&ChildStatus) == -1) {
return make_error<Failure>(
@@ -317,11 +373,23 @@
if (ChildExitCode == 0) {
// The child exited succesfully, read counter values and return
// success
- CounterValues[0] = Counter->read();
+ auto CounterValueOrErr = Counter->readOrError();
+ if (!CounterValueOrErr)
+ return CounterValueOrErr.takeError();
+ CounterValues = std::move(*CounterValueOrErr);
+
+ auto ValidationValuesOrErr = Counter->readValidationCountersOrError();
+ if (!ValidationValuesOrErr)
+ return ValidationValuesOrErr.takeError();
+
+ ArrayRef RealValidationValues = *ValidationValuesOrErr;
+ for (size_t I = 0; I < RealValidationValues.size(); ++I)
+ ValidationCounterValues[I] = RealValidationValues[I];
+
return Error::success();
}
// The child exited, but not successfully
- return make_error<SnippetCrash>(
+ return make_error<Failure>(
"Child benchmarking process exited with non-zero exit code: " +
childProcessExitCodeToString(ChildExitCode));
}
@@ -334,13 +402,28 @@
Twine(strerror(errno)));
}
- return make_error<SnippetCrash>(
- "The benchmarking subprocess sent unexpected signal: " +
- Twine(strsignal(ChildSignalInfo.si_signo)));
+ if (ChildSignalInfo.si_signo == SIGSEGV)
+ return make_error<SnippetSegmentationFault>(
+ reinterpret_cast<intptr_t>(ChildSignalInfo.si_addr));
+
+ return make_error<SnippetSignal>(ChildSignalInfo.si_signo);
+ }
+
+ void disableCoreDumps() const {
+ struct rlimit rlim;
+
+ rlim.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
}
[[noreturn]] void prepareAndRunBenchmark(int Pipe,
const BenchmarkKey &Key) const {
+ // Disable core dumps in the child process as otherwise everytime we
+ // encounter an execution failure like a segmentation fault, we will create
+ // a core dump. We report the information directly rather than require the
+ // user inspect a core dump.
+ disableCoreDumps();
+
// The following occurs within the benchmarking subprocess
pid_t ParentPID = getppid();
@@ -364,10 +447,24 @@
exit(ChildProcessExitCodeE::RSeqDisableFailed);
#endif // GLIBC_INITS_RSEQ
+ // The frontend that generates the memory annotation structures should
+ // validate that the address to map the snippet in at is a multiple of
+ // the page size. Assert that this is true here.
+ assert(Key.SnippetAddress % getpagesize() == 0 &&
+ "The snippet address needs to be aligned to a page boundary.");
+
size_t FunctionDataCopySize = this->Function.FunctionBytes.size();
+ void *MapAddress = NULL;
+ int MapFlags = MAP_PRIVATE | MAP_ANONYMOUS;
+
+ if (Key.SnippetAddress != 0) {
+ MapAddress = reinterpret_cast<void *>(Key.SnippetAddress);
+ MapFlags |= MAP_FIXED_NOREPLACE;
+ }
+
char *FunctionDataCopy =
- (char *)mmap(NULL, FunctionDataCopySize, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ (char *)mmap(MapAddress, FunctionDataCopySize, PROT_READ | PROT_WRITE,
+ MapFlags, 0, 0);
if ((intptr_t)FunctionDataCopy == -1)
exit(ChildProcessExitCodeE::FunctionDataMappingFailed);
@@ -387,15 +484,15 @@
exit(0);
}
- Expected<llvm::SmallVector<int64_t, 4>>
- runWithCounter(StringRef CounterName) const override {
+ Expected<llvm::SmallVector<int64_t, 4>> runWithCounter(
+ StringRef CounterName, ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const override {
SmallVector<int64_t, 4> Value(1, 0);
- Error PossibleBenchmarkError =
- createSubProcessAndRunBenchmark(CounterName, Value);
+ Error PossibleBenchmarkError = createSubProcessAndRunBenchmark(
+ CounterName, Value, ValidationCounters, ValidationCounterValues);
- if (PossibleBenchmarkError) {
+ if (PossibleBenchmarkError)
return std::move(PossibleBenchmarkError);
- }
return Value;
}
@@ -416,7 +513,6 @@
raw_svector_ostream OS(Buffer);
if (Error E = assembleToStream(
State.getExegesisTarget(), State.createTargetMachine(), BC.LiveIns,
- BC.Key.RegisterInitialValues,
Repetitor.Repeat(Instructions, MinInstructions, LoopBodySize,
GenerateMemoryInstructions),
OS, BC.Key, GenerateMemoryInstructions)) {
@@ -431,19 +527,20 @@
const SnippetRepetitor &Repetitor) const {
RunnableConfiguration RC;
- Benchmark &InstrBenchmark = RC.InstrBenchmark;
- InstrBenchmark.Mode = Mode;
- InstrBenchmark.CpuName = std::string(State.getTargetMachine().getTargetCPU());
- InstrBenchmark.LLVMTriple =
+ Benchmark &BenchmarkResult = RC.BenchmarkResult;
+ BenchmarkResult.Mode = Mode;
+ BenchmarkResult.CpuName =
+ std::string(State.getTargetMachine().getTargetCPU());
+ BenchmarkResult.LLVMTriple =
State.getTargetMachine().getTargetTriple().normalize();
- InstrBenchmark.NumRepetitions = NumRepetitions;
- InstrBenchmark.Info = BC.Info;
+ BenchmarkResult.NumRepetitions = NumRepetitions;
+ BenchmarkResult.Info = BC.Info;
const std::vector<MCInst> &Instructions = BC.Key.Instructions;
bool GenerateMemoryInstructions = ExecutionMode == ExecutionModeE::SubProcess;
- InstrBenchmark.Key = BC.Key;
+ BenchmarkResult.Key = BC.Key;
// Assemble at least kMinInstructionsForSnippet instructions by repeating
// the snippet for debug/analysis. This is so that the user clearly
@@ -458,7 +555,7 @@
return std::move(E);
if (auto Err = getBenchmarkFunctionBytes(*Snippet,
- InstrBenchmark.AssembledSnippet))
+ BenchmarkResult.AssembledSnippet))
return std::move(Err);
}
@@ -466,8 +563,9 @@
// measurements.
if (BenchmarkPhaseSelector >
BenchmarkPhaseSelectorE::PrepareAndAssembleSnippet) {
- auto Snippet = assembleSnippet(BC, Repetitor, InstrBenchmark.NumRepetitions,
- LoopBodySize, GenerateMemoryInstructions);
+ auto Snippet =
+ assembleSnippet(BC, Repetitor, BenchmarkResult.NumRepetitions,
+ LoopBodySize, GenerateMemoryInstructions);
if (Error E = Snippet.takeError())
return std::move(E);
RC.ObjectFile = getObjectFromBuffer(*Snippet);
@@ -481,25 +579,35 @@
object::OwningBinary<object::ObjectFile> ObjectFile,
const BenchmarkKey &Key) const {
switch (ExecutionMode) {
- case ExecutionModeE::InProcess:
- return std::make_unique<InProcessFunctionExecutorImpl>(
+ case ExecutionModeE::InProcess: {
+ auto InProcessExecutorOrErr = InProcessFunctionExecutorImpl::create(
State, std::move(ObjectFile), Scratch.get());
- case ExecutionModeE::SubProcess:
+ if (!InProcessExecutorOrErr)
+ return InProcessExecutorOrErr.takeError();
+
+ return std::move(*InProcessExecutorOrErr);
+ }
+ case ExecutionModeE::SubProcess: {
#ifdef __linux__
- return std::make_unique<SubProcessFunctionExecutorImpl>(
+ auto SubProcessExecutorOrErr = SubProcessFunctionExecutorImpl::create(
State, std::move(ObjectFile), Key);
+ if (!SubProcessExecutorOrErr)
+ return SubProcessExecutorOrErr.takeError();
+
+ return std::move(*SubProcessExecutorOrErr);
#else
return make_error<Failure>(
"The subprocess execution mode is only supported on Linux");
#endif
}
+ }
llvm_unreachable("ExecutionMode is outside expected range");
}
-Expected<Benchmark> BenchmarkRunner::runConfiguration(
+std::pair<Error, Benchmark> BenchmarkRunner::runConfiguration(
RunnableConfiguration &&RC,
const std::optional<StringRef> &DumpFile) const {
- Benchmark &InstrBenchmark = RC.InstrBenchmark;
+ Benchmark &BenchmarkResult = RC.BenchmarkResult;
object::OwningBinary<object::ObjectFile> &ObjectFile = RC.ObjectFile;
if (DumpFile && BenchmarkPhaseSelector >
@@ -507,42 +615,38 @@
auto ObjectFilePath =
writeObjectFile(ObjectFile.getBinary()->getData(), *DumpFile);
if (Error E = ObjectFilePath.takeError()) {
- InstrBenchmark.Error = toString(std::move(E));
- return std::move(InstrBenchmark);
+ return {std::move(E), std::move(BenchmarkResult)};
}
outs() << "Check generated assembly with: /usr/bin/objdump -d "
<< *ObjectFilePath << "\n";
}
if (BenchmarkPhaseSelector < BenchmarkPhaseSelectorE::Measure) {
- InstrBenchmark.Error = "actual measurements skipped.";
- return std::move(InstrBenchmark);
+ BenchmarkResult.Error = "actual measurements skipped.";
+ return {Error::success(), std::move(BenchmarkResult)};
}
Expected<std::unique_ptr<BenchmarkRunner::FunctionExecutor>> Executor =
- createFunctionExecutor(std::move(ObjectFile), RC.InstrBenchmark.Key);
+ createFunctionExecutor(std::move(ObjectFile), RC.BenchmarkResult.Key);
if (!Executor)
- return Executor.takeError();
+ return {Executor.takeError(), std::move(BenchmarkResult)};
auto NewMeasurements = runMeasurements(**Executor);
if (Error E = NewMeasurements.takeError()) {
- if (!E.isA<SnippetCrash>())
- return std::move(E);
- InstrBenchmark.Error = toString(std::move(E));
- return std::move(InstrBenchmark);
+ return {std::move(E), std::move(BenchmarkResult)};
}
- assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
+ assert(BenchmarkResult.NumRepetitions > 0 && "invalid NumRepetitions");
for (BenchmarkMeasure &BM : *NewMeasurements) {
// Scale the measurements by instruction.
- BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
+ BM.PerInstructionValue /= BenchmarkResult.NumRepetitions;
// Scale the measurements by snippet.
- BM.PerSnippetValue *=
- static_cast<double>(InstrBenchmark.Key.Instructions.size()) /
- InstrBenchmark.NumRepetitions;
+ BM.PerSnippetValue /=
+ std::ceil(BenchmarkResult.NumRepetitions /
+ static_cast<double>(BenchmarkResult.Key.Instructions.size()));
}
- InstrBenchmark.Measurements = std::move(*NewMeasurements);
+ BenchmarkResult.Measurements = std::move(*NewMeasurements);
- return std::move(InstrBenchmark);
+ return {Error::success(), std::move(BenchmarkResult)};
}
Expected<std::string>
@@ -559,7 +663,35 @@
raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
OFS.write(Buffer.data(), Buffer.size());
OFS.flush();
- return std::string(ResultPath.str());
+ return std::string(ResultPath);
+}
+
+static bool EventLessThan(const std::pair<ValidationEvent, const char *> LHS,
+ const ValidationEvent RHS) {
+ return static_cast<int>(LHS.first) < static_cast<int>(RHS);
+}
+
+Error BenchmarkRunner::getValidationCountersToRun(
+ SmallVector<const char *> &ValCountersToRun) const {
+ const PfmCountersInfo &PCI = State.getPfmCounters();
+ ValCountersToRun.reserve(ValidationCounters.size());
+
+ ValCountersToRun.reserve(ValidationCounters.size());
+ ArrayRef TargetValidationEvents(PCI.ValidationEvents,
+ PCI.NumValidationEvents);
+ for (const ValidationEvent RequestedValEvent : ValidationCounters) {
+ auto ValCounterIt =
+ lower_bound(TargetValidationEvents, RequestedValEvent, EventLessThan);
+ if (ValCounterIt == TargetValidationEvents.end() ||
+ ValCounterIt->first != RequestedValEvent)
+ return make_error<Failure>("Cannot create validation counter");
+
+ assert(ValCounterIt->first == RequestedValEvent &&
+ "The array of validation events from the target should be sorted");
+ ValCountersToRun.push_back(ValCounterIt->second);
+ }
+
+ return Error::success();
}
BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
index 24f2086..aab4b54 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
@@ -38,7 +38,8 @@
explicit BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- ExecutionModeE ExecutionMode);
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters);
virtual ~BenchmarkRunner();
@@ -56,7 +57,7 @@
private:
RunnableConfiguration() = default;
- Benchmark InstrBenchmark;
+ Benchmark BenchmarkResult;
object::OwningBinary<object::ObjectFile> ObjectFile;
};
@@ -65,7 +66,7 @@
unsigned NumRepetitions, unsigned LoopUnrollFactor,
const SnippetRepetitor &Repetitor) const;
- Expected<Benchmark>
+ std::pair<Error, Benchmark>
runConfiguration(RunnableConfiguration &&RC,
const std::optional<StringRef> &DumpFile) const;
@@ -93,14 +94,18 @@
virtual ~FunctionExecutor();
Expected<llvm::SmallVector<int64_t, 4>>
- runAndSample(const char *Counters) const;
+ runAndSample(const char *Counters,
+ ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const;
protected:
static void
accumulateCounterValues(const llvm::SmallVectorImpl<int64_t> &NewValues,
llvm::SmallVectorImpl<int64_t> *Result);
virtual Expected<llvm::SmallVector<int64_t, 4>>
- runWithCounter(StringRef CounterName) const = 0;
+ runWithCounter(StringRef CounterName,
+ ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const = 0;
};
protected:
@@ -109,6 +114,11 @@
const BenchmarkPhaseSelectorE BenchmarkPhaseSelector;
const ExecutionModeE ExecutionMode;
+ SmallVector<ValidationEvent> ValidationCounters;
+
+ Error
+ getValidationCountersToRun(SmallVector<const char *> &ValCountersToRun) const;
+
private:
virtual Expected<std::vector<BenchmarkMeasure>>
runMeasurements(const FunctionExecutor &Executor) const = 0;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
index 92135e6..7312811 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
@@ -29,10 +29,10 @@
MC
MCA
MCDisassembler
- MCJIT
MCParser
Object
ObjectYAML
+ OrcJIT
RuntimeDyld
Support
TargetParser
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.cpp
index c702462..1f1fca4 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.cpp
@@ -307,10 +307,8 @@
assert(std::distance(it, OldCluster.PointIndices.end()) > 0 &&
"Should have found at least one bad point");
// Mark to-be-moved points as belonging to the new cluster.
- std::for_each(it, OldCluster.PointIndices.end(),
- [this, &UnstableCluster](size_t P) {
- ClusterIdForPoint_[P] = UnstableCluster.Id;
- });
+ for (size_t P : llvm::make_range(it, OldCluster.PointIndices.end()))
+ ClusterIdForPoint_[P] = UnstableCluster.Id;
// Actually append to-be-moved points to the new cluster.
UnstableCluster.PointIndices.insert(UnstableCluster.PointIndices.end(),
it, OldCluster.PointIndices.end());
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.cpp
index 51ce41b..82ef92d 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.cpp
@@ -8,6 +8,11 @@
#include "Error.h"
+#ifdef LLVM_ON_UNIX
+#include "llvm/Support/SystemZ/zOSSupport.h"
+#include <string.h>
+#endif // LLVM_ON_UNIX
+
namespace llvm {
namespace exegesis {
@@ -19,13 +24,29 @@
return inconvertibleErrorCode();
}
-char SnippetCrash::ID;
+char SnippetExecutionFailure::ID;
-void SnippetCrash::log(raw_ostream &OS) const { OS << Msg; }
-
-std::error_code SnippetCrash::convertToErrorCode() const {
+std::error_code SnippetExecutionFailure::convertToErrorCode() const {
return inconvertibleErrorCode();
}
+char SnippetSegmentationFault::ID;
+
+void SnippetSegmentationFault::log(raw_ostream &OS) const {
+ OS << "The snippet encountered a segmentation fault at address "
+ << Twine::utohexstr(Address);
+}
+
+char SnippetSignal::ID;
+
+void SnippetSignal::log(raw_ostream &OS) const {
+ OS << "snippet crashed while running";
+#ifdef LLVM_ON_UNIX
+ OS << ": " << strsignal(SignalNumber);
+#else
+ (void)SignalNumber;
+#endif // LLVM_ON_UNIX
+}
+
} // namespace exegesis
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.h
index e5fa093e..2587c45 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Error.h
@@ -36,19 +36,44 @@
std::string Msg;
};
-// A class representing failures that happened during snippet execution.
-// Instead of terminating the program crashes are logged into the output.
-class SnippetCrash : public ErrorInfo<SnippetCrash> {
+// A class representing a non-descript snippet execution failure. This class
+// is designed to sub-classed into more specific failures that contain
+// additional data about the specific error that they represent. Instead of
+// halting the program, the errors are reported in the output.
+class SnippetExecutionFailure : public ErrorInfo<SnippetExecutionFailure> {
public:
static char ID;
- SnippetCrash(const Twine &S) : Msg(S.str()) {}
+
+ std::error_code convertToErrorCode() const override;
+};
+
+// A class representing specifically segmentation faults that happen during
+// snippet execution.
+class SnippetSegmentationFault : public SnippetExecutionFailure {
+public:
+ static char ID;
+ SnippetSegmentationFault(intptr_t SegFaultAddress)
+ : Address(SegFaultAddress){};
+
+ intptr_t getAddress() { return Address; }
void log(raw_ostream &OS) const override;
- std::error_code convertToErrorCode() const override;
+private:
+ intptr_t Address;
+};
+
+// A class representing all other non-specific failures that happen during
+// snippet execution.
+class SnippetSignal : public SnippetExecutionFailure {
+public:
+ static char ID;
+ SnippetSignal(int Signal) : SignalNumber(Signal){};
+
+ void log(raw_ostream &OS) const override;
private:
- std::string Msg;
+ int SignalNumber;
};
} // namespace exegesis
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
index 753efed..eb7f70f 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
@@ -21,11 +21,14 @@
LatencyBenchmarkRunner::LatencyBenchmarkRunner(
const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- Benchmark::ResultAggregationModeE ResultAgg, ExecutionModeE ExecutionMode)
- : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector, ExecutionMode) {
+ Benchmark::ResultAggregationModeE ResultAgg, ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters, unsigned BenchmarkRepeatCount)
+ : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector, ExecutionMode,
+ ValCounters) {
assert((Mode == Benchmark::Latency || Mode == Benchmark::InverseThroughput) &&
"invalid mode");
ResultAggMode = ResultAgg;
+ NumMeasurements = BenchmarkRepeatCount;
}
LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
@@ -68,14 +71,23 @@
// Cycle measurements include some overhead from the kernel. Repeat the
// measure several times and return the aggregated value, as specified by
// ResultAggMode.
- constexpr const int NumMeasurements = 30;
llvm::SmallVector<int64_t, 4> AccumulatedValues;
double MinVariance = std::numeric_limits<double>::infinity();
- const char *CounterName = State.getPfmCounters().CycleCounter;
+ const PfmCountersInfo &PCI = State.getPfmCounters();
+ const char *CounterName = PCI.CycleCounter;
+
+ SmallVector<const char *> ValCountersToRun;
+ Error ValCounterErr = getValidationCountersToRun(ValCountersToRun);
+ if (ValCounterErr)
+ return std::move(ValCounterErr);
+
+ SmallVector<int64_t> ValCounterValues(ValCountersToRun.size(), 0);
// Values count for each run.
int ValuesCount = 0;
for (size_t I = 0; I < NumMeasurements; ++I) {
- auto ExpectedCounterValues = Executor.runAndSample(CounterName);
+ SmallVector<int64_t> IterationValCounterValues(ValCountersToRun.size(), -1);
+ auto ExpectedCounterValues = Executor.runAndSample(
+ CounterName, ValCountersToRun, IterationValCounterValues);
if (!ExpectedCounterValues)
return ExpectedCounterValues.takeError();
ValuesCount = ExpectedCounterValues.get().size();
@@ -89,8 +101,15 @@
MinVariance = Variance;
}
}
+
+ for (size_t I = 0; I < ValCounterValues.size(); ++I)
+ ValCounterValues[I] += IterationValCounterValues[I];
}
+ std::map<ValidationEvent, int64_t> ValidationInfo;
+ for (size_t I = 0; I < ValidationCounters.size(); ++I)
+ ValidationInfo[ValidationCounters[I]] = ValCounterValues[I];
+
std::string ModeName;
switch (Mode) {
case Benchmark::Latency:
@@ -111,25 +130,26 @@
std::vector<BenchmarkMeasure> Result;
Result.reserve(AccumulatedValues.size());
for (const int64_t Value : AccumulatedValues)
- Result.push_back(BenchmarkMeasure::Create(ModeName, Value));
+ Result.push_back(
+ BenchmarkMeasure::Create(ModeName, Value, ValidationInfo));
return std::move(Result);
}
case Benchmark::Min: {
std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMin(AccumulatedValues)));
+ Result.push_back(BenchmarkMeasure::Create(
+ ModeName, findMin(AccumulatedValues), ValidationInfo));
return std::move(Result);
}
case Benchmark::Max: {
std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMax(AccumulatedValues)));
+ Result.push_back(BenchmarkMeasure::Create(
+ ModeName, findMax(AccumulatedValues), ValidationInfo));
return std::move(Result);
}
case Benchmark::Mean: {
std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMean(AccumulatedValues)));
+ Result.push_back(BenchmarkMeasure::Create(
+ ModeName, findMean(AccumulatedValues), ValidationInfo));
return std::move(Result);
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
index 34b912f..6e21197 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
@@ -15,6 +15,7 @@
#define LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H
#include "BenchmarkRunner.h"
+#include "Target.h"
namespace llvm {
namespace exegesis {
@@ -24,7 +25,9 @@
LatencyBenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
- ExecutionModeE ExecutionMode);
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters,
+ unsigned BenchmarkRepeatCount);
~LatencyBenchmarkRunner() override;
private:
@@ -32,6 +35,7 @@
runMeasurements(const FunctionExecutor &Executor) const override;
Benchmark::ResultAggregationModeE ResultAggMode;
+ unsigned NumMeasurements;
};
} // namespace exegesis
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.h
index 137ba1b..16f0def 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.h
@@ -16,7 +16,6 @@
#include "MCInstrDescView.h"
#include "RegisterAliasing.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
index f453731..d781605 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
@@ -9,7 +9,6 @@
#include "MCInstrDescView.h"
#include <iterator>
-#include <map>
#include <tuple>
#include "llvm/ADT/STLExtras.h"
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
index ec698e6..cc8cd5d 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
@@ -11,6 +11,9 @@
#include "Mips.h"
#include "MipsRegisterInfo.h"
+#define GET_AVAILABLE_OPCODE_CHECKER
+#include "MipsGenInstrInfo.inc"
+
namespace llvm {
namespace exegesis {
@@ -51,7 +54,8 @@
namespace {
class ExegesisMipsTarget : public ExegesisTarget {
public:
- ExegesisMipsTarget() : ExegesisTarget(MipsCpuPfmCounters) {}
+ ExegesisMipsTarget()
+ : ExegesisTarget(MipsCpuPfmCounters, Mips_MC::isOpcodeAvailable) {}
private:
unsigned getScratchMemoryRegister(const llvm::Triple &TT) const override;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/MmapUtils.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MmapUtils.h
new file mode 100644
index 0000000..31e8778
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MmapUtils.h
@@ -0,0 +1,32 @@
+//===-- MmapUtils.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains compatibility-related preprocessor directives related
+// to mmap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef __linux__
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+// Before kernel 4.17, Linux did not support MAP_FIXED_NOREPLACE, so if it is
+// not available, simplfy define it as MAP_FIXED which performs the same
+// function but does not guarantee existing mappings won't get clobbered.
+#ifndef MAP_FIXED_NOREPLACE
+#define MAP_FIXED_NOREPLACE MAP_FIXED
+#endif
+
+// Some 32-bit architectures don't have mmap and define mmap2 instead. The only
+// difference between the two syscalls is that mmap2's offset parameter is in
+// terms 4096 byte offsets rather than individual bytes, so for our purposes
+// they are effectively the same as all ofsets here are set to 0.
+#if defined(SYS_mmap2) && !defined(SYS_mmap)
+#define SYS_mmap SYS_mmap2
+#endif
+#endif // __linux__
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
index 3ff1745..6b8df01 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
@@ -107,20 +107,17 @@
return FullQualifiedEventString;
}
-Counter::Counter(PerfEvent &&E, pid_t ProcessID) : Event(std::move(E)) {
+ConfiguredEvent::ConfiguredEvent(PerfEvent &&EventToConfigure)
+ : Event(std::move(EventToConfigure)) {
assert(Event.valid());
- IsDummyEvent = Event.name() == PerfEvent::DummyEventString;
- if (!IsDummyEvent)
- initRealEvent(E, ProcessID);
}
#ifdef HAVE_LIBPFM
-void Counter::initRealEvent(const PerfEvent &E, pid_t ProcessID) {
- const int Cpu = -1; // measure any processor.
- const int GroupFd = -1; // no grouping of counters.
+void ConfiguredEvent::initRealEvent(const pid_t ProcessID, const int GroupFD) {
+ const int CPU = -1;
const uint32_t Flags = 0;
perf_event_attr AttrCopy = *Event.attribute();
- FileDescriptor = perf_event_open(&AttrCopy, ProcessID, Cpu, GroupFd, Flags);
+ FileDescriptor = perf_event_open(&AttrCopy, ProcessID, CPU, GroupFD, Flags);
if (FileDescriptor == -1) {
errs() << "Unable to open event. ERRNO: " << strerror(errno)
<< ". Make sure your kernel allows user "
@@ -133,64 +130,101 @@
assert(FileDescriptor != -1 && "Unable to open event");
}
-Counter::~Counter() {
- if (!IsDummyEvent)
- close(FileDescriptor);
-}
-
-void Counter::start() {
- if (!IsDummyEvent)
- ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0);
-}
-
-void Counter::stop() {
- if (!IsDummyEvent)
- ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0);
-}
-
-int64_t Counter::read() const {
- auto ValueOrError = readOrError();
- if (ValueOrError) {
- if (!ValueOrError.get().empty())
- return ValueOrError.get()[0];
- errs() << "Counter has no reading\n";
- } else
- errs() << ValueOrError.takeError() << "\n";
- return -1;
-}
-
-llvm::Expected<llvm::SmallVector<int64_t, 4>>
-Counter::readOrError(StringRef /*unused*/) const {
+Expected<SmallVector<int64_t>>
+ConfiguredEvent::readOrError(StringRef /*unused*/) const {
int64_t Count = 0;
- if (!IsDummyEvent) {
- ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
- if (ReadSize != sizeof(Count))
- return llvm::make_error<llvm::StringError>("Failed to read event counter",
- llvm::errc::io_error);
- } else {
- Count = 42;
- }
+ ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
- llvm::SmallVector<int64_t, 4> Result;
+ if (ReadSize != sizeof(Count))
+ return llvm::make_error<llvm::StringError>("Failed to read event counter",
+ llvm::errc::io_error);
+
+ SmallVector<int64_t, 1> Result;
Result.push_back(Count);
return Result;
}
-int Counter::numValues() const { return 1; }
+ConfiguredEvent::~ConfiguredEvent() { close(FileDescriptor); }
#else
+void ConfiguredEvent::initRealEvent(pid_t ProcessID, const int GroupFD) {}
-void Counter::initRealEvent(const PerfEvent &, pid_t ProcessID) {}
+Expected<SmallVector<int64_t>>
+ConfiguredEvent::readOrError(StringRef /*unused*/) const {
+ return make_error<StringError>("Not implemented",
+ errc::function_not_supported);
+}
-Counter::~Counter() = default;
+ConfiguredEvent::~ConfiguredEvent() = default;
+#endif // HAVE_LIBPFM
-void Counter::start() {}
+CounterGroup::CounterGroup(PerfEvent &&E, std::vector<PerfEvent> &&ValEvents,
+ pid_t ProcessID)
+ : EventCounter(std::move(E)) {
+ IsDummyEvent = EventCounter.isDummyEvent();
-void Counter::stop() {}
+ for (auto &&ValEvent : ValEvents)
+ ValidationEventCounters.emplace_back(std::move(ValEvent));
-int64_t Counter::read() const { return 42; }
+ if (!IsDummyEvent)
+ initRealEvent(ProcessID);
+}
+
+#ifdef HAVE_LIBPFM
+void CounterGroup::initRealEvent(pid_t ProcessID) {
+ EventCounter.initRealEvent(ProcessID);
+
+ for (auto &ValCounter : ValidationEventCounters)
+ ValCounter.initRealEvent(ProcessID, getFileDescriptor());
+}
+
+void CounterGroup::start() {
+ if (!IsDummyEvent)
+ ioctl(getFileDescriptor(), PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
+}
+
+void CounterGroup::stop() {
+ if (!IsDummyEvent)
+ ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
+}
llvm::Expected<llvm::SmallVector<int64_t, 4>>
-Counter::readOrError(StringRef /*unused*/) const {
+CounterGroup::readOrError(StringRef FunctionBytes) const {
+ if (!IsDummyEvent)
+ return EventCounter.readOrError(FunctionBytes);
+ else
+ return SmallVector<int64_t, 1>(1, 42);
+}
+
+llvm::Expected<llvm::SmallVector<int64_t>>
+CounterGroup::readValidationCountersOrError() const {
+ llvm::SmallVector<int64_t, 4> Result;
+ for (const auto &ValCounter : ValidationEventCounters) {
+ Expected<SmallVector<int64_t>> ValueOrError =
+ ValCounter.readOrError(StringRef());
+
+ if (!ValueOrError)
+ return ValueOrError.takeError();
+
+ // Reading a validation counter will only return a single value, so it is
+ // safe to only append the first value here. Also assert that this is true.
+ assert(ValueOrError->size() == 1 &&
+ "Validation counters should only return a single value");
+ Result.push_back((*ValueOrError)[0]);
+ }
+ return Result;
+}
+
+int CounterGroup::numValues() const { return 1; }
+#else
+
+void CounterGroup::initRealEvent(pid_t ProcessID) {}
+
+void CounterGroup::start() {}
+
+void CounterGroup::stop() {}
+
+llvm::Expected<llvm::SmallVector<int64_t, 4>>
+CounterGroup::readOrError(StringRef /*unused*/) const {
if (IsDummyEvent) {
llvm::SmallVector<int64_t, 4> Result;
Result.push_back(42);
@@ -200,7 +234,12 @@
llvm::errc::io_error);
}
-int Counter::numValues() const { return 1; }
+llvm::Expected<llvm::SmallVector<int64_t>>
+CounterGroup::readValidationCountersOrError() const {
+ return SmallVector<int64_t>(0);
+}
+
+int CounterGroup::numValues() const { return 1; }
#endif
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.h
index a50974f..7d050b8 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PerfHelper.h
@@ -77,17 +77,43 @@
void initRealEvent(StringRef PfmEventString);
};
-// Uses a valid PerfEvent to configure the Kernel so we can measure the
-// underlying event.
-class Counter {
+// Represents a single event that has been configured in the Linux perf
+// subsystem.
+class ConfiguredEvent {
+public:
+ ConfiguredEvent(PerfEvent &&EventToConfigure);
+
+ void initRealEvent(const pid_t ProcessID, const int GroupFD = -1);
+ Expected<SmallVector<int64_t>> readOrError(StringRef FunctionBytes) const;
+ int getFileDescriptor() const { return FileDescriptor; }
+ bool isDummyEvent() const {
+ return Event.name() == PerfEvent::DummyEventString;
+ }
+
+ ConfiguredEvent(const ConfiguredEvent &) = delete;
+ ConfiguredEvent(ConfiguredEvent &&other) = default;
+
+ ~ConfiguredEvent();
+
+private:
+ PerfEvent Event;
+ int FileDescriptor = -1;
+};
+
+// Consists of a counter measuring a specific event and associated validation
+// counters measuring execution conditions. All counters in a group are part
+// of a single event group and are thus scheduled on and off the CPU as a single
+// unit.
+class CounterGroup {
public:
// event: the PerfEvent to measure.
- explicit Counter(PerfEvent &&event, pid_t ProcessID = 0);
+ explicit CounterGroup(PerfEvent &&event, std::vector<PerfEvent> &&ValEvents,
+ pid_t ProcessID = 0);
- Counter(const Counter &) = delete;
- Counter(Counter &&other) = default;
+ CounterGroup(const CounterGroup &) = delete;
+ CounterGroup(CounterGroup &&other) = default;
- virtual ~Counter();
+ virtual ~CounterGroup() = default;
/// Starts the measurement of the event.
virtual void start();
@@ -95,9 +121,6 @@
/// Stops the measurement of the event.
void stop();
- /// Returns the current value of the counter or -1 if it cannot be read.
- int64_t read() const;
-
/// Returns the current value of the counter or error if it cannot be read.
/// FunctionBytes: The benchmark function being executed.
/// This is used to filter out the measurements to ensure they are only
@@ -107,17 +130,20 @@
virtual llvm::Expected<llvm::SmallVector<int64_t, 4>>
readOrError(StringRef FunctionBytes = StringRef()) const;
+ virtual llvm::Expected<llvm::SmallVector<int64_t>>
+ readValidationCountersOrError() const;
+
virtual int numValues() const;
- int getFileDescriptor() const { return FileDescriptor; }
+ int getFileDescriptor() const { return EventCounter.getFileDescriptor(); }
protected:
- PerfEvent Event;
- int FileDescriptor = -1;
+ ConfiguredEvent EventCounter;
bool IsDummyEvent;
+ std::vector<ConfiguredEvent> ValidationEventCounters;
private:
- void initRealEvent(const PerfEvent &E, pid_t ProcessID);
+ void initRealEvent(pid_t ProcessID);
};
} // namespace pfm
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
index 54d42df..5c944c9 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
@@ -10,6 +10,9 @@
#include "PPC.h"
#include "PPCRegisterInfo.h"
+#define GET_AVAILABLE_OPCODE_CHECKER
+#include "PPCGenInstrInfo.inc"
+
namespace llvm {
namespace exegesis {
@@ -26,7 +29,8 @@
namespace {
class ExegesisPowerPCTarget : public ExegesisTarget {
public:
- ExegesisPowerPCTarget() : ExegesisTarget(PPCCpuPfmCounters) {}
+ ExegesisPowerPCTarget()
+ : ExegesisTarget(PPCCpuPfmCounters, PPC_MC::isOpcodeAvailable) {}
private:
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
index 6b768c8..5910757 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
@@ -12,8 +12,6 @@
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MCA/Support.h"
#include "llvm/Support/FormatVariadic.h"
-#include <limits>
-#include <unordered_set>
#include <vector>
namespace llvm {
@@ -83,19 +81,20 @@
const MCWriteProcResEntry *WPR = Entry.second;
const MCProcResourceDesc *const ProcResDesc =
SM.getProcResource(WPR->ProcResourceIdx);
- // TODO: Handle StartAtCycle in llvm-exegesis and llvm-mca. See
+ // TODO: Handle AcquireAtAtCycle in llvm-exegesis and llvm-mca. See
// https://github.com/llvm/llvm-project/issues/62680 and
// https://github.com/llvm/llvm-project/issues/62681
- assert(WPR->StartAtCycle == 0 &&
- "`llvm-exegesis` does not handle StartAtCycle > 0");
+ assert(WPR->AcquireAtCycle == 0 &&
+ "`llvm-exegesis` does not handle AcquireAtCycle > 0");
if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
// This is a ProcResUnit.
- Result.push_back({WPR->ProcResourceIdx, WPR->Cycles, WPR->StartAtCycle});
- ProcResUnitUsage[WPR->ProcResourceIdx] += WPR->Cycles;
+ Result.push_back(
+ {WPR->ProcResourceIdx, WPR->ReleaseAtCycle, WPR->AcquireAtCycle});
+ ProcResUnitUsage[WPR->ProcResourceIdx] += WPR->ReleaseAtCycle;
} else {
// This is a ProcResGroup. First see if it contributes any cycles or if
// it has cycles just from subunits.
- float RemainingCycles = WPR->Cycles;
+ float RemainingCycles = WPR->ReleaseAtCycle;
for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;
++SubResIdx) {
@@ -108,7 +107,7 @@
// The ProcResGroup contributes `RemainingCycles` cycles of its own.
Result.push_back({WPR->ProcResourceIdx,
static_cast<uint16_t>(std::round(RemainingCycles)),
- WPR->StartAtCycle});
+ WPR->AcquireAtCycle});
// Spread the remaining cycles over all subunits.
for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;
@@ -213,13 +212,13 @@
SM.getProcResource(WPR.ProcResourceIdx);
if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
// This is a ProcResUnit.
- DensePressure[WPR.ProcResourceIdx] += WPR.Cycles;
+ DensePressure[WPR.ProcResourceIdx] += WPR.ReleaseAtCycle;
} else {
// This is a ProcResGroup.
SmallVector<uint16_t, 32> Subunits(ProcResDesc->SubUnitsIdxBegin,
ProcResDesc->SubUnitsIdxBegin +
ProcResDesc->NumUnits);
- distributePressure(WPR.Cycles, Subunits, DensePressure);
+ distributePressure(WPR.ReleaseAtCycle, Subunits, DensePressure);
}
}
// Turn dense pressure into sparse pressure by removing zero entries.
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
index 07a009c..7100b51 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
@@ -38,6 +38,8 @@
computeAliasingInstructions(const LLVMState &State, const Instruction *Instr,
size_t MaxAliasingInstructions,
const BitVector &ForbiddenRegisters) {
+ const auto &ET = State.getExegesisTarget();
+ const auto AvailableFeatures = State.getSubtargetInfo().getFeatureBits();
// Randomly iterate the set of instructions.
std::vector<unsigned> Opcodes;
Opcodes.resize(State.getInstrInfo().getNumOpcodes());
@@ -46,6 +48,8 @@
std::vector<const Instruction *> AliasingInstructions;
for (const unsigned OtherOpcode : Opcodes) {
+ if (!ET.isOpcodeAvailable(OtherOpcode, AvailableFeatures))
+ continue;
if (OtherOpcode == Instr->Description.getOpcode())
continue;
const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode);
@@ -58,7 +62,7 @@
}
if (OtherInstr.hasMemoryOperands())
continue;
- if (!State.getExegesisTarget().allowAsBackToBack(OtherInstr))
+ if (!ET.allowAsBackToBack(OtherInstr))
continue;
if (Instr->hasAliasingRegistersThrough(OtherInstr, ForbiddenRegisters))
AliasingInstructions.push_back(&OtherInstr);
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
index d85a9f1..7258fcb 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -23,6 +23,10 @@
#include "llvm/Support/SourceMgr.h"
#include <string>
+#ifdef __linux__
+#include <unistd.h>
+#endif // __linux__
+
namespace llvm {
namespace exegesis {
namespace {
@@ -118,6 +122,19 @@
MemoryMapping MemMap;
MemMap.MemoryValueName = Parts[0].trim().str();
MemMap.Address = std::stol(Parts[1].trim().str());
+
+#ifdef __linux__
+ // Validate that the annotation is a multiple of the platform's page
+ // size.
+ if (MemMap.Address % getpagesize() != 0) {
+ errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText
+ << "', expected <ADDRESS> to be a multiple of the platform page "
+ "size.";
+ ++InvalidComments;
+ return;
+ }
+#endif // __linux__
+
// validate that the annotation refers to an already existing memory
// definition
auto MemValIT = Result->Key.MemoryValues.find(Parts[0].trim().str());
@@ -131,6 +148,33 @@
Result->Key.MemoryMappings.push_back(std::move(MemMap));
return;
}
+ if (CommentText.consume_front("SNIPPET-ADDRESS")) {
+ // LLVM-EXEGESIS-SNIPPET-ADDRESS <address>
+ if (!to_integer<intptr_t>(CommentText.trim(), Result->Key.SnippetAddress,
+ 16)) {
+ errs() << "invalid comment 'LLVM-EXEGESIS-SNIPPET-ADDRESS "
+ << CommentText
+ << "', expected <ADDRESS> to contain a valid integer in "
+ "hexadecimal format";
+ ++InvalidComments;
+ return;
+ }
+
+#ifdef __linux__
+ // Validate that the address in the annotation is a multiple of the
+ // platform's page size.
+ if (Result->Key.SnippetAddress % getpagesize() != 0) {
+ errs() << "invalid comment 'LLVM-EXEGESIS-SNIPPET-ADDRESS "
+ << CommentText
+ << ", expected <ADDRESS> to be a multiple of the platform page "
+ "size.";
+ ++InvalidComments;
+ return;
+ }
+#endif // __linux__
+
+ return;
+ }
}
unsigned numInvalidComments() const { return InvalidComments; }
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
index 4b47be0..7dcff60 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
@@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//
-#include <array>
#include <string>
#include "Assembler.h"
@@ -17,6 +16,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Program.h"
@@ -77,9 +77,12 @@
BC.Info = CT.Info;
BC.Key.Instructions.reserve(CT.Instructions.size());
for (InstructionTemplate &IT : CT.Instructions) {
- if (auto error = randomizeUnsetVariables(State, ForbiddenRegs, IT))
- return error;
- BC.Key.Instructions.push_back(IT.build());
+ if (auto Error = randomizeUnsetVariables(State, ForbiddenRegs, IT))
+ return Error;
+ MCInst Inst = IT.build();
+ if (auto Error = validateGeneratedInstruction(State, Inst))
+ return Error;
+ BC.Key.Instructions.push_back(Inst);
}
if (CT.ScratchSpacePointerInReg)
BC.LiveIns.push_back(CT.ScratchSpacePointerInReg);
@@ -282,5 +285,21 @@
return Error::success();
}
+Error validateGeneratedInstruction(const LLVMState &State, const MCInst &Inst) {
+ for (const auto &Operand : Inst) {
+ if (!Operand.isValid()) {
+ // Mention the particular opcode - it is not necessarily the "main"
+ // opcode being benchmarked by this snippet. For example, serial snippet
+ // generator uses one more opcode when in SERIAL_VIA_NON_MEMORY_INSTR
+ // execution mode.
+ const auto OpcodeName = State.getInstrInfo().getName(Inst.getOpcode());
+ return make_error<Failure>("Not all operands were initialized by the "
+ "snippet generator for " +
+ OpcodeName + " opcode.");
+ }
+ }
+ return Error::success();
+}
+
} // namespace exegesis
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h
index 9c64d46..770e4e8 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h
@@ -107,6 +107,9 @@
const BitVector &ForbiddenRegs,
InstructionTemplate &IT);
+// Sanity check generated instruction.
+Error validateGeneratedInstruction(const LLVMState &State, const MCInst &Inst);
+
} // namespace exegesis
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp
index 8b0c452..c1660c2 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp
@@ -6,13 +6,11 @@
//
//===----------------------------------------------------------------------===//
-#include <array>
-#include <string>
-
#include "SnippetRepetitor.h"
#include "Target.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
namespace llvm {
@@ -32,10 +30,10 @@
CleanupMemory](FunctionFiller &Filler) {
auto Entry = Filler.getEntry();
if (!Instructions.empty()) {
- // Add the whole snippet at least once.
- Entry.addInstructions(Instructions);
- for (unsigned I = Instructions.size(); I < MinInstructions; ++I) {
- Entry.addInstruction(Instructions[I % Instructions.size()]);
+ const unsigned NumRepetitions =
+ divideCeil(MinInstructions, Instructions.size());
+ for (unsigned I = 0; I < NumRepetitions; ++I) {
+ Entry.addInstructions(Instructions);
}
}
Entry.addReturn(State.getExegesisTarget(), CleanupMemory);
@@ -77,6 +75,11 @@
auto Loop = Filler.addBasicBlock();
auto Exit = Filler.addBasicBlock();
+ // Align the loop machine basic block to a target-specific boundary
+ // to promote optimal instruction fetch/predecoding conditions.
+ Loop.MBB->setAlignment(
+ Filler.MF.getSubtarget().getTargetLowering()->getPrefLoopAlignment());
+
const unsigned LoopUnrollFactor =
LoopBodySize <= Instructions.size()
? 1
@@ -106,7 +109,7 @@
for (const auto &LiveIn : Entry.MBB->liveins())
Loop.MBB->addLiveIn(LiveIn);
}
- for (auto _ : seq(0U, LoopUnrollFactor)) {
+ for (auto _ : seq(LoopUnrollFactor)) {
(void)_;
Loop.addInstructions(Instructions);
}
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp
index 1e5f688..58cf1b9 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp
@@ -14,6 +14,7 @@
#include "UopsBenchmarkRunner.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
namespace llvm {
namespace exegesis {
@@ -34,8 +35,9 @@
return nullptr;
}
-Expected<std::unique_ptr<pfm::Counter>>
+Expected<std::unique_ptr<pfm::CounterGroup>>
ExegesisTarget::createCounter(StringRef CounterName, const LLVMState &,
+ ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID) const {
pfm::PerfEvent Event(CounterName);
if (!Event.valid())
@@ -44,7 +46,18 @@
.concat(CounterName)
.concat("'"));
- return std::make_unique<pfm::Counter>(std::move(Event), ProcessID);
+ std::vector<pfm::PerfEvent> ValidationEvents;
+ for (const char *ValCounterName : ValidationCounters) {
+ ValidationEvents.emplace_back(ValCounterName);
+ if (!ValidationEvents.back().valid())
+ return llvm::make_error<Failure>(
+ llvm::Twine("Unable to create validation counter with name '")
+ .concat(ValCounterName)
+ .concat("'"));
+ }
+
+ return std::make_unique<pfm::CounterGroup>(
+ std::move(Event), std::move(ValidationEvents), ProcessID);
}
void ExegesisTarget::registerTarget(ExegesisTarget *Target) {
@@ -78,6 +91,7 @@
Benchmark::ModeE Mode, const LLVMState &State,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
BenchmarkRunner::ExecutionModeE ExecutionMode,
+ unsigned BenchmarkRepeatCount, ArrayRef<ValidationEvent> ValidationCounters,
Benchmark::ResultAggregationModeE ResultAggMode) const {
PfmCountersInfo PfmCounters = State.getPfmCounters();
switch (Mode) {
@@ -99,8 +113,9 @@
"benchmarking or --use-dummy-perf-counters to not query "
"the kernel for real event counts."));
}
- return createLatencyBenchmarkRunner(State, Mode, BenchmarkPhaseSelector,
- ResultAggMode, ExecutionMode);
+ return createLatencyBenchmarkRunner(
+ State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,
+ ValidationCounters, BenchmarkRepeatCount);
case Benchmark::Uops:
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
!PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
@@ -110,7 +125,8 @@
"benchmarking or --use-dummy-perf-counters to not query the kernel "
"for real event counts.");
return createUopsBenchmarkRunner(State, BenchmarkPhaseSelector,
- ResultAggMode, ExecutionMode);
+ ResultAggMode, ExecutionMode,
+ ValidationCounters);
}
return nullptr;
}
@@ -129,25 +145,34 @@
const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
- BenchmarkRunner::ExecutionModeE ExecutionMode) const {
+ BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters,
+ unsigned BenchmarkRepeatCount) const {
return std::make_unique<LatencyBenchmarkRunner>(
- State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode);
+ State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,
+ ValidationCounters, BenchmarkRepeatCount);
}
std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner(
const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE /*unused*/,
- BenchmarkRunner::ExecutionModeE ExecutionMode) const {
- return std::make_unique<UopsBenchmarkRunner>(State, BenchmarkPhaseSelector,
- ExecutionMode);
+ BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters) const {
+ return std::make_unique<UopsBenchmarkRunner>(
+ State, BenchmarkPhaseSelector, ExecutionMode, ValidationCounters);
}
static_assert(std::is_trivial_v<PfmCountersInfo>,
"We shouldn't have dynamic initialization here");
+
const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,
- 0u};
+ 0u, nullptr, 0u};
const PfmCountersInfo PfmCountersInfo::Dummy = {
- pfm::PerfEvent::DummyEventString, pfm::PerfEvent::DummyEventString, nullptr,
+ pfm::PerfEvent::DummyEventString,
+ pfm::PerfEvent::DummyEventString,
+ nullptr,
+ 0u,
+ nullptr,
0u};
const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const {
@@ -180,10 +205,12 @@
namespace {
+bool opcodeIsNotAvailable(unsigned, const FeatureBitset &) { return false; }
+
// Default implementation.
class ExegesisDefaultTarget : public ExegesisTarget {
public:
- ExegesisDefaultTarget() : ExegesisTarget({}) {}
+ ExegesisDefaultTarget() : ExegesisTarget({}, opcodeIsNotAvailable) {}
private:
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.h
index 986ad98..3d6169c 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.h
@@ -29,6 +29,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
#include "llvm/TargetParser/Triple.h"
namespace llvm {
@@ -58,6 +59,9 @@
const IssueCounter *IssueCounters;
unsigned NumIssueCounters;
+ const std::pair<ValidationEvent, const char *> *ValidationEvents;
+ unsigned NumValidationEvents;
+
static const PfmCountersInfo Default;
static const PfmCountersInfo Dummy;
};
@@ -70,12 +74,15 @@
class ExegesisTarget {
public:
- explicit ExegesisTarget(ArrayRef<CpuAndPfmCounters> CpuPfmCounters)
- : CpuPfmCounters(CpuPfmCounters) {}
+ typedef bool (*OpcodeAvailabilityChecker)(unsigned, const FeatureBitset &);
+ ExegesisTarget(ArrayRef<CpuAndPfmCounters> CpuPfmCounters,
+ OpcodeAvailabilityChecker IsOpcodeAvailable)
+ : CpuPfmCounters(CpuPfmCounters), IsOpcodeAvailable(IsOpcodeAvailable) {}
// Targets can use this to create target-specific perf counters.
- virtual Expected<std::unique_ptr<pfm::Counter>>
+ virtual Expected<std::unique_ptr<pfm::CounterGroup>>
createCounter(StringRef CounterName, const LLVMState &State,
+ ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID = 0) const;
// Targets can use this to add target-specific passes in assembleToStream();
@@ -139,6 +146,12 @@
"current architecture\n");
}
+ // Returns true if all features are available that are required by Opcode.
+ virtual bool isOpcodeAvailable(unsigned Opcode,
+ const FeatureBitset &Features) const {
+ return IsOpcodeAvailable(Opcode, Features);
+ }
+
// Sets the stack register to the auxiliary memory so that operations
// requiring the stack can be formed (e.g., setting large registers). The code
// generated by this function may clobber registers.
@@ -253,6 +266,8 @@
Benchmark::ModeE Mode, const LLVMState &State,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
BenchmarkRunner::ExecutionModeE ExecutionMode,
+ unsigned BenchmarkRepeatCount,
+ ArrayRef<ValidationEvent> ValidationCounters,
Benchmark::ResultAggregationModeE ResultAggMode = Benchmark::Min) const;
// Returns the ExegesisTarget for the given triple or nullptr if the target
@@ -296,14 +311,18 @@
const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
- BenchmarkRunner::ExecutionModeE ExecutionMode) const;
+ BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters,
+ unsigned BenchmarkRepeatCount) const;
std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner(
const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
- BenchmarkRunner::ExecutionModeE ExecutionMode) const;
+ BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters) const;
const ExegesisTarget *Next = nullptr;
const ArrayRef<CpuAndPfmCounters> CpuPfmCounters;
+ const OpcodeAvailabilityChecker IsOpcodeAvailable;
};
} // namespace exegesis
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
index 6351fdd..d6fb599 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
@@ -19,25 +19,45 @@
UopsBenchmarkRunner::runMeasurements(const FunctionExecutor &Executor) const {
std::vector<BenchmarkMeasure> Result;
const PfmCountersInfo &PCI = State.getPfmCounters();
+
+ SmallVector<const char *> ValCountersToRun;
+ Error ValCounterErr = getValidationCountersToRun(ValCountersToRun);
+ if (ValCounterErr)
+ return std::move(ValCounterErr);
+
// Uops per port.
for (const auto *IssueCounter = PCI.IssueCounters,
*IssueCounterEnd = PCI.IssueCounters + PCI.NumIssueCounters;
IssueCounter != IssueCounterEnd; ++IssueCounter) {
+ SmallVector<int64_t> ValCounterPortValues(ValCountersToRun.size(), -1);
if (!IssueCounter->Counter)
continue;
- auto ExpectedCounterValue = Executor.runAndSample(IssueCounter->Counter);
+ auto ExpectedCounterValue = Executor.runAndSample(
+ IssueCounter->Counter, ValCountersToRun, ValCounterPortValues);
if (!ExpectedCounterValue)
return ExpectedCounterValue.takeError();
- Result.push_back(BenchmarkMeasure::Create(IssueCounter->ProcResName,
- (*ExpectedCounterValue)[0]));
+
+ std::map<ValidationEvent, int64_t> ValidationInfo;
+ for (size_t I = 0; I < ValidationCounters.size(); ++I)
+ ValidationInfo[ValidationCounters[I]] = ValCounterPortValues[I];
+
+ Result.push_back(BenchmarkMeasure::Create(
+ IssueCounter->ProcResName, (*ExpectedCounterValue)[0], ValidationInfo));
}
// NumMicroOps.
if (const char *const UopsCounter = PCI.UopsCounter) {
- auto ExpectedCounterValue = Executor.runAndSample(UopsCounter);
+ SmallVector<int64_t> ValCounterUopsValues(ValCountersToRun.size(), -1);
+ auto ExpectedCounterValue = Executor.runAndSample(
+ UopsCounter, ValCountersToRun, ValCounterUopsValues);
if (!ExpectedCounterValue)
return ExpectedCounterValue.takeError();
- Result.push_back(
- BenchmarkMeasure::Create("NumMicroOps", (*ExpectedCounterValue)[0]));
+
+ std::map<ValidationEvent, int64_t> ValidationInfo;
+ for (size_t I = 0; I < ValidationCounters.size(); ++I)
+ ValidationInfo[ValidationCounters[I]] = ValCounterUopsValues[I];
+
+ Result.push_back(BenchmarkMeasure::Create(
+ "NumMicroOps", (*ExpectedCounterValue)[0], ValidationInfo));
}
return std::move(Result);
}
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
index 337f093..ef47b7f 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
@@ -15,6 +15,7 @@
#define LLVM_TOOLS_LLVM_EXEGESIS_UOPSBENCHMARKRUNNER_H
#include "BenchmarkRunner.h"
+#include "Target.h"
namespace llvm {
namespace exegesis {
@@ -23,9 +24,10 @@
public:
UopsBenchmarkRunner(const LLVMState &State,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- ExecutionModeE ExecutionMode)
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters)
: BenchmarkRunner(State, Benchmark::Uops, BenchmarkPhaseSelector,
- ExecutionMode) {}
+ ExecutionMode, ValCounters) {}
~UopsBenchmarkRunner() override;
static constexpr const size_t kMinNumDifferentAddresses = 6;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index b3d4080..adb345f 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -8,6 +8,7 @@
#include "../Target.h"
#include "../Error.h"
+#include "../MmapUtils.h"
#include "../ParallelSnippetGenerator.h"
#include "../SerialSnippetGenerator.h"
#include "../SnippetGenerator.h"
@@ -38,11 +39,20 @@
#endif
#ifdef __linux__
+#ifdef __x86_64__
+#include <asm/prctl.h>
+#endif // __x86_64__
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
+#ifdef HAVE_LIBPFM
+#include <perfmon/perf_event.h>
+#endif // HAVE_LIBPFM
#endif
+#define GET_AVAILABLE_OPCODE_CHECKER
+#include "X86GenInstrInfo.inc"
+
namespace llvm {
namespace exegesis {
@@ -207,9 +217,9 @@
const auto OpcodeName = Instr.Name;
if ((Instr.Description.TSFlags & X86II::FormMask) == X86II::Pseudo)
return "unsupported opcode: pseudo instruction";
- if ((OpcodeName.startswith("POP") && !OpcodeName.startswith("POPCNT")) ||
- OpcodeName.startswith("PUSH") || OpcodeName.startswith("ADJCALLSTACK") ||
- OpcodeName.startswith("LEAVE"))
+ if ((OpcodeName.starts_with("POP") && !OpcodeName.starts_with("POPCNT")) ||
+ OpcodeName.starts_with("PUSH") ||
+ OpcodeName.starts_with("ADJCALLSTACK") || OpcodeName.starts_with("LEAVE"))
return "unsupported opcode: Push/Pop/AdjCallStack/Leave";
switch (Instr.Description.Opcode) {
case X86::LFS16rm:
@@ -669,10 +679,12 @@
class ExegesisX86Target : public ExegesisTarget {
public:
- ExegesisX86Target() : ExegesisTarget(X86CpuPfmCounters) {}
+ ExegesisX86Target()
+ : ExegesisTarget(X86CpuPfmCounters, X86_MC::isOpcodeAvailable) {}
- Expected<std::unique_ptr<pfm::Counter>>
+ Expected<std::unique_ptr<pfm::CounterGroup>>
createCounter(StringRef CounterName, const LLVMState &State,
+ ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID) const override {
// If LbrSamplingPeriod was provided, then ignore the
// CounterName because we only have one for LBR.
@@ -681,6 +693,13 @@
// __linux__ (for now)
#if defined(HAVE_LIBPFM) && defined(LIBPFM_HAS_FIELD_CYCLES) && \
defined(__linux__)
+ // TODO(boomanaiden154): Add in support for using validation counters when
+ // using LBR counters.
+ if (ValidationCounters.size() > 0)
+ return llvm::make_error<llvm::StringError>(
+ "Using LBR is not currently supported with validation counters",
+ llvm::errc::invalid_argument);
+
return std::make_unique<X86LbrCounter>(
X86LbrPerfEvent(LbrSamplingPeriod));
#else
@@ -690,7 +709,8 @@
llvm::errc::invalid_argument);
#endif
}
- return ExegesisTarget::createCounter(CounterName, State, ProcessID);
+ return ExegesisTarget::createCounter(CounterName, State, ValidationCounters,
+ ProcessID);
}
enum ArgumentRegisters { CodeSize = X86::R12, AuxiliaryMemoryFD = X86::R13 };
@@ -902,9 +922,94 @@
.addImm(X86::COND_NE);
}
+void generateRegisterStackPush(unsigned int Register,
+ std::vector<MCInst> &GeneratedCode) {
+ GeneratedCode.push_back(MCInstBuilder(X86::PUSH64r).addReg(Register));
+}
+
+void generateRegisterStackPop(unsigned int Register,
+ std::vector<MCInst> &GeneratedCode) {
+ GeneratedCode.push_back(MCInstBuilder(X86::POP64r).addReg(Register));
+}
+
+void generateSyscall(long SyscallNumber, std::vector<MCInst> &GeneratedCode) {
+ GeneratedCode.push_back(
+ loadImmediate(X86::RAX, 64, APInt(64, SyscallNumber)));
+ GeneratedCode.push_back(MCInstBuilder(X86::SYSCALL));
+}
+
+// The functions below for saving and restoring system call registers are only
+// used when llvm-exegesis is built on Linux.
+#ifdef __linux__
+constexpr std::array<unsigned, 6> SyscallArgumentRegisters{
+ X86::RDI, X86::RSI, X86::RDX, X86::R10, X86::R8, X86::R9};
+
+static void saveSyscallRegisters(std::vector<MCInst> &GeneratedCode,
+ unsigned ArgumentCount) {
+ assert(ArgumentCount <= 6 &&
+ "System calls only X86-64 Linux can only take six arguments");
+ // Preserve RCX and R11 (Clobbered by the system call).
+ generateRegisterStackPush(X86::RCX, GeneratedCode);
+ generateRegisterStackPush(X86::R11, GeneratedCode);
+ // Preserve RAX (used for the syscall number/return value).
+ generateRegisterStackPush(X86::RAX, GeneratedCode);
+ // Preserve the registers used to pass arguments to the system call.
+ for (unsigned I = 0; I < ArgumentCount; ++I)
+ generateRegisterStackPush(SyscallArgumentRegisters[I], GeneratedCode);
+}
+
+static void restoreSyscallRegisters(std::vector<MCInst> &GeneratedCode,
+ unsigned ArgumentCount) {
+ assert(ArgumentCount <= 6 &&
+ "System calls only X86-64 Linux can only take six arguments");
+ // Restore the argument registers, in the opposite order of the way they are
+ // saved.
+ for (unsigned I = ArgumentCount; I > 0; --I) {
+ generateRegisterStackPop(SyscallArgumentRegisters[I - 1], GeneratedCode);
+ }
+ generateRegisterStackPop(X86::RAX, GeneratedCode);
+ generateRegisterStackPop(X86::R11, GeneratedCode);
+ generateRegisterStackPop(X86::RCX, GeneratedCode);
+}
+#endif // __linux__
+
+static std::vector<MCInst> loadImmediateSegmentRegister(unsigned Reg,
+ const APInt &Value) {
+#if defined(__x86_64__) && defined(__linux__)
+ assert(Value.getBitWidth() <= 64 && "Value must fit in the register.");
+ std::vector<MCInst> loadSegmentRegisterCode;
+ // Preserve the syscall registers here as we don't
+ // want to make any assumptions about the ordering of what registers are
+ // loaded in first, and we might have already loaded in registers that we are
+ // going to be clobbering here.
+ saveSyscallRegisters(loadSegmentRegisterCode, 2);
+ // Generate the instructions to make the arch_prctl system call to set
+ // the registers.
+ int SyscallCode = 0;
+ if (Reg == X86::FS)
+ SyscallCode = ARCH_SET_FS;
+ else if (Reg == X86::GS)
+ SyscallCode = ARCH_SET_GS;
+ else
+ llvm_unreachable("Only the segment registers GS and FS are supported");
+ loadSegmentRegisterCode.push_back(
+ loadImmediate(X86::RDI, 64, APInt(64, SyscallCode)));
+ loadSegmentRegisterCode.push_back(loadImmediate(X86::RSI, 64, Value));
+ generateSyscall(SYS_arch_prctl, loadSegmentRegisterCode);
+ // Restore the registers in reverse order
+ restoreSyscallRegisters(loadSegmentRegisterCode, 2);
+ return loadSegmentRegisterCode;
+#else
+ llvm_unreachable("Loading immediate segment registers is only supported with "
+ "x86-64 llvm-exegesis");
+#endif // defined(__x86_64__) && defined(__linux__)
+}
+
std::vector<MCInst> ExegesisX86Target::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
+ if (X86::SEGMENT_REGRegClass.contains(Reg))
+ return loadImmediateSegmentRegister(Reg, Value);
if (X86::GR8RegClass.contains(Reg))
return {loadImmediate(Reg, 8, Value)};
if (X86::GR16RegClass.contains(Reg))
@@ -987,12 +1092,6 @@
static constexpr const intptr_t VAddressSpaceCeiling = 0x0000800000000000;
#endif
-void generateSyscall(long SyscallNumber, std::vector<MCInst> &GeneratedCode) {
- GeneratedCode.push_back(
- loadImmediate(X86::RAX, 64, APInt(64, SyscallNumber)));
- GeneratedCode.push_back(MCInstBuilder(X86::SYSCALL));
-}
-
void generateRoundToNearestPage(unsigned int Register,
std::vector<MCInst> &GeneratedCode) {
int PageSizeShift = static_cast<int>(round(log2(getpagesize())));
@@ -1076,21 +1175,6 @@
return ExitCallCode;
}
-// Before kernel 4.17, Linux did not support MAP_FIXED_NOREPLACE, so if it is
-// not available, simplfy define it as MAP_FIXED which performs the same
-// function but does not guarantee existing mappings won't get clobbered.
-#ifndef MAP_FIXED_NOREPLACE
-#define MAP_FIXED_NOREPLACE MAP_FIXED
-#endif
-
-// Some 32-bit architectures don't have mmap and define mmap2 instead. The only
-// difference between the two syscalls is that mmap2's offset parameter is in
-// terms 4096 byte offsets rather than individual bytes, so for our purposes
-// they are effectively the same as all ofsets here are set to 0.
-#if defined(SYS_mmap2) && !defined(SYS_mmap)
-#define SYS_mmap SYS_mmap2
-#endif
-
std::vector<MCInst>
ExegesisX86Target::generateMmap(intptr_t Address, size_t Length,
intptr_t FileDescriptorAddress) const {
@@ -1167,25 +1251,11 @@
return VAddressSpaceCeiling - 2 * getpagesize();
}
-void generateRegisterStackPush(unsigned int Register,
- std::vector<MCInst> &GeneratedCode) {
- GeneratedCode.push_back(MCInstBuilder(X86::PUSH64r).addReg(Register));
-}
-
-void generateRegisterStackPop(unsigned int Register,
- std::vector<MCInst> &GeneratedCode) {
- GeneratedCode.push_back(MCInstBuilder(X86::POP64r).addReg(Register));
-}
-
std::vector<MCInst>
ExegesisX86Target::configurePerfCounter(long Request, bool SaveRegisters) const {
std::vector<MCInst> ConfigurePerfCounterCode;
- if(SaveRegisters) {
- // Preservie RAX, RDI, and RSI by pushing them to the stack.
- generateRegisterStackPush(X86::RAX, ConfigurePerfCounterCode);
- generateRegisterStackPush(X86::RDI, ConfigurePerfCounterCode);
- generateRegisterStackPush(X86::RSI, ConfigurePerfCounterCode);
- }
+ if (SaveRegisters)
+ saveSyscallRegisters(ConfigurePerfCounterCode, 3);
ConfigurePerfCounterCode.push_back(
loadImmediate(X86::RDI, 64, APInt(64, getAuxiliaryMemoryStartAddress())));
ConfigurePerfCounterCode.push_back(MCInstBuilder(X86::MOV32rm)
@@ -1197,13 +1267,13 @@
.addReg(0));
ConfigurePerfCounterCode.push_back(
loadImmediate(X86::RSI, 64, APInt(64, Request)));
+#ifdef HAVE_LIBPFM
+ ConfigurePerfCounterCode.push_back(
+ loadImmediate(X86::RDX, 64, APInt(64, PERF_IOC_FLAG_GROUP)));
+#endif // HAVE_LIBPFM
generateSyscall(SYS_ioctl, ConfigurePerfCounterCode);
- if(SaveRegisters) {
- // Restore RAX, RDI, and RSI, in reverse order.
- generateRegisterStackPop(X86::RSI, ConfigurePerfCounterCode);
- generateRegisterStackPop(X86::RIP, ConfigurePerfCounterCode);
- generateRegisterStackPop(X86::RAX, ConfigurePerfCounterCode);
- }
+ if (SaveRegisters)
+ restoreSyscallRegisters(ConfigurePerfCounterCode, 3);
return ConfigurePerfCounterCode;
}
@@ -1212,7 +1282,7 @@
}
std::vector<unsigned> ExegesisX86Target::getRegistersNeedSaving() const {
- return {X86::RAX, X86::RDI, X86::RSI};
+ return {X86::RAX, X86::RDI, X86::RSI, X86::RCX, X86::R11};
}
#endif // __linux__
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
index 3fee0e5..26be9f8 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
@@ -87,7 +87,8 @@
continue;
}
DataPtr += sizeof(Header);
- uint64_t Count = llvm::support::endian::read64(DataPtr, support::native);
+ uint64_t Count =
+ llvm::support::endian::read64(DataPtr, llvm::endianness::native);
DataPtr += sizeof(Count);
struct perf_branch_entry Entry;
@@ -140,9 +141,9 @@
}
X86LbrCounter::X86LbrCounter(pfm::PerfEvent &&NewEvent)
- : Counter(std::move(NewEvent)) {
+ : CounterGroup(std::move(NewEvent), {}) {
MMappedBuffer = mmap(nullptr, kMappedBufferSize, PROT_READ | PROT_WRITE,
- MAP_SHARED, FileDescriptor, 0);
+ MAP_SHARED, getFileDescriptor(), 0);
if (MMappedBuffer == MAP_FAILED)
llvm::errs() << "Failed to mmap buffer.";
}
@@ -153,7 +154,7 @@
}
void X86LbrCounter::start() {
- ioctl(FileDescriptor, PERF_EVENT_IOC_REFRESH, 1024 /* kMaxPollsPerFd */);
+ ioctl(getFileDescriptor(), PERF_EVENT_IOC_REFRESH, 1024 /* kMaxPollsPerFd */);
}
llvm::Error X86LbrCounter::checkLbrSupport() {
@@ -196,7 +197,7 @@
llvm::Expected<llvm::SmallVector<int64_t, 4>>
X86LbrCounter::readOrError(StringRef FunctionBytes) const {
// Disable the event before reading
- ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0);
+ ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE, 0);
// Find the boundary of the function so that we could filter the LBRs
// to keep only the relevant records.
@@ -222,7 +223,7 @@
int PollResult = 0;
while (PollResult <= 0) {
- PollResult = pollLbrPerfEvent(FileDescriptor);
+ PollResult = pollLbrPerfEvent(getFileDescriptor());
if (PollResult > 0)
break;
if (PollResult == -1)
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.h
index 73e4dc5..bc2fced 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/X86Counter.h
@@ -31,7 +31,7 @@
X86LbrPerfEvent(unsigned SamplingPeriod);
};
-class X86LbrCounter : public pfm::Counter {
+class X86LbrCounter : public pfm::CounterGroup {
public:
static llvm::Error checkLbrSupport();
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index ff868e7..9b3fe76 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -262,6 +262,34 @@
"allows for the use of memory annotations")),
cl::init(BenchmarkRunner::ExecutionModeE::InProcess));
+static cl::opt<unsigned> BenchmarkRepeatCount(
+ "benchmark-repeat-count",
+ cl::desc("The number of times to repeat measurements on the benchmark k "
+ "before aggregating the results"),
+ cl::cat(BenchmarkOptions), cl::init(30));
+
+static cl::list<ValidationEvent> ValidationCounters(
+ "validation-counter",
+ cl::desc(
+ "The name of a validation counter to run concurrently with the main "
+ "counter to validate benchmarking assumptions"),
+ cl::CommaSeparated, cl::cat(BenchmarkOptions),
+ cl::values(
+ clEnumValN(ValidationEvent::InstructionRetired, "instructions-retired",
+ "Count retired instructions"),
+ clEnumValN(ValidationEvent::L1DCacheLoadMiss, "l1d-cache-load-misses",
+ "Count L1D load cache misses"),
+ clEnumValN(ValidationEvent::L1DCacheStoreMiss, "l1d-cache-store-misses",
+ "Count L1D store cache misses"),
+ clEnumValN(ValidationEvent::L1ICacheLoadMiss, "l1i-cache-load-misses",
+ "Count L1I load cache misses"),
+ clEnumValN(ValidationEvent::DataTLBLoadMiss, "data-tlb-load-misses",
+ "Count DTLB load misses"),
+ clEnumValN(ValidationEvent::DataTLBStoreMiss, "data-tlb-store-misses",
+ "Count DTLB store misses"),
+ clEnumValN(ValidationEvent::InstructionTLBLoadMiss,
+ "instruction-tlb-load-misses", "Count ITLB load misses")));
+
static ExitOnError ExitOnErr("llvm-exegesis error: ");
// Helper function that logs the error(s) and exits.
@@ -291,6 +319,9 @@
const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) +
(OpcodeIndex == 0 ? 0 : 1) +
(SnippetsFile.empty() ? 0 : 1);
+ const auto &ET = State.getExegesisTarget();
+ const auto AvailableFeatures = State.getSubtargetInfo().getFeatureBits();
+
if (NumSetFlags != 1) {
ExitOnErr.setBanner("llvm-exegesis: ");
ExitWithError("please provide one and only one of 'opcode-index', "
@@ -304,8 +335,11 @@
std::vector<unsigned> Result;
unsigned NumOpcodes = State.getInstrInfo().getNumOpcodes();
Result.reserve(NumOpcodes);
- for (unsigned I = 0, E = NumOpcodes; I < E; ++I)
+ for (unsigned I = 0, E = NumOpcodes; I < E; ++I) {
+ if (!ET.isOpcodeAvailable(I, AvailableFeatures))
+ continue;
Result.push_back(I);
+ }
return Result;
}
// Resolve opcode name -> opcode.
@@ -398,8 +432,18 @@
std::optional<StringRef> DumpFile;
if (DumpObjectToDisk.getNumOccurrences())
DumpFile = DumpObjectToDisk;
- AllResults.emplace_back(
- ExitOnErr(Runner.runConfiguration(std::move(RC), DumpFile)));
+ auto [Err, BenchmarkResult] =
+ Runner.runConfiguration(std::move(RC), DumpFile);
+ if (Err) {
+ // Errors from executing the snippets are fine.
+ // All other errors are a framework issue and should fail.
+ if (!Err.isA<SnippetExecutionFailure>()) {
+ llvm::errs() << "llvm-exegesis error: " << toString(std::move(Err));
+ exit(1);
+ }
+ BenchmarkResult.Error = toString(std::move(Err));
+ }
+ AllResults.push_back(std::move(BenchmarkResult));
}
Benchmark &Result = AllResults.front();
@@ -415,7 +459,7 @@
ArrayRef<Benchmark>(AllResults).drop_front()) {
llvm::append_range(Result.AssembledSnippet,
OtherResult.AssembledSnippet);
- // Aggregate measurements, but only iff all measurements succeeded.
+ // Aggregate measurements, but only if all measurements succeeded.
if (Result.Measurements.empty())
continue;
assert(OtherResult.Measurements.size() == Result.Measurements.size() &&
@@ -471,10 +515,15 @@
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure)
ExitOnErr(State.getExegesisTarget().checkFeatureSupport());
+ if (ExecutionMode == BenchmarkRunner::ExecutionModeE::SubProcess &&
+ UseDummyPerfCounters)
+ ExitWithError("Dummy perf counters are not supported in the subprocess "
+ "execution mode.");
+
const std::unique_ptr<BenchmarkRunner> Runner =
ExitOnErr(State.getExegesisTarget().createBenchmarkRunner(
BenchmarkMode, State, BenchmarkPhaseSelector, ExecutionMode,
- ResultAggMode));
+ BenchmarkRepeatCount, ValidationCounters, ResultAggMode));
if (!Runner) {
ExitWithError("cannot create benchmark runner");
}
@@ -492,11 +541,8 @@
}
BitVector AllReservedRegs;
- llvm::for_each(Repetitors,
- [&AllReservedRegs](
- const std::unique_ptr<const SnippetRepetitor> &Repetitor) {
- AllReservedRegs |= Repetitor->getReservedRegs();
- });
+ for (const std::unique_ptr<const SnippetRepetitor> &Repetitor : Repetitors)
+ AllReservedRegs |= Repetitor->getReservedRegs();
std::vector<BenchmarkCode> Configurations;
if (!Opcodes.empty()) {
@@ -525,8 +571,10 @@
for (const auto &Configuration : Configurations) {
if (ExecutionMode != BenchmarkRunner::ExecutionModeE::SubProcess &&
(Configuration.Key.MemoryMappings.size() != 0 ||
- Configuration.Key.MemoryValues.size() != 0))
- ExitWithError("Memory annotations are only supported in subprocess "
+ Configuration.Key.MemoryValues.size() != 0 ||
+ Configuration.Key.SnippetAddress != 0))
+ ExitWithError("Memory and snippet address annotations are only "
+ "supported in subprocess "
"execution mode");
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/src/llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index 307248c..e5ae726 100644
--- a/src/llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/Archive.h"
@@ -32,7 +31,6 @@
#include <cstring>
#include <inttypes.h>
#include <iostream>
-#include <map>
#include <optional>
#include <string>
#include <system_error>
@@ -58,9 +56,7 @@
using namespace llvm::opt;
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -73,13 +69,7 @@
#undef PREFIX
const opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -221,14 +211,14 @@
Triple ObjTriple(Obj.getArchTriple());
StringRef ObjArch = ObjTriple.getArchName();
- for (auto Arch : ArchFilters) {
+ for (StringRef Arch : ArchFilters) {
// Match name.
if (Arch == ObjArch)
return true;
// Match architecture number.
unsigned Value;
- if (!StringRef(Arch).getAsInteger(0, Value))
+ if (!Arch.getAsInteger(0, Value))
if (Value == getCPUType(Obj))
return true;
}
@@ -238,7 +228,7 @@
/// Determine the virtual address that is considered the base address of an ELF
/// object file.
///
-/// The base address of an ELF file is the the "p_vaddr" of the first program
+/// The base address of an ELF file is the "p_vaddr" of the first program
/// header whose "p_type" is PT_LOAD.
///
/// \param ELFFile An ELF object file we will search.
@@ -315,6 +305,11 @@
auto ThreadCount =
NumThreads > 0 ? NumThreads : std::thread::hardware_concurrency();
auto &OS = outs();
+ // Make a stream refernce that will become a /dev/null log stream if
+ // Quiet is true, or normal output if Quiet is false. This can stop the
+ // errors and warnings from being displayed and producing too much output
+ // when they aren't desired.
+ raw_ostream *LogOS = Quiet ? nullptr : &outs();
GsymCreator Gsym(Quiet);
@@ -340,23 +335,30 @@
}
// Make sure there is DWARF to convert first.
- std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(Obj);
+ std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
+ Obj,
+ /*RelocAction=*/DWARFContext::ProcessDebugRelocations::Process,
+ nullptr,
+ /*DWPName=*/"",
+ /*RecoverableErrorHandler=*/WithColor::defaultErrorHandler,
+ /*WarningHandler=*/WithColor::defaultWarningHandler,
+ /*ThreadSafe*/true);
if (!DICtx)
return createStringError(std::errc::invalid_argument,
"unable to create DWARF context");
// Make a DWARF transformer object and populate the ranges of the code
// so we don't end up adding invalid functions to GSYM data.
- DwarfTransformer DT(*DICtx, OS, Gsym);
+ DwarfTransformer DT(*DICtx, Gsym);
if (!TextRanges.empty())
Gsym.SetValidTextRanges(TextRanges);
// Convert all DWARF to GSYM.
- if (auto Err = DT.convert(ThreadCount))
+ if (auto Err = DT.convert(ThreadCount, LogOS))
return Err;
// Get the UUID and convert symbol table to GSYM.
- if (auto Err = ObjectFileTransformer::convert(Obj, OS, Gsym))
+ if (auto Err = ObjectFileTransformer::convert(Obj, LogOS, Gsym))
return Err;
// Finalize the GSYM to make it ready to save to disk. This will remove
@@ -366,8 +368,9 @@
return Err;
// Save the GSYM file to disk.
- support::endianness Endian =
- Obj.makeTriple().isLittleEndian() ? support::little : support::big;
+ llvm::endianness Endian = Obj.makeTriple().isLittleEndian()
+ ? llvm::endianness::little
+ : llvm::endianness::big;
std::optional<uint64_t> OptSegmentSize;
if (SegmentSize > 0)
@@ -378,7 +381,7 @@
// Verify the DWARF if requested. This will ensure all the info in the DWARF
// can be looked up in the GSYM and that all lookups get matching data.
if (Verify) {
- if (auto Err = DT.verify(OutFile))
+ if (auto Err = DT.verify(OutFile, OS))
return Err;
}
@@ -465,10 +468,9 @@
error(DsymObjectsOrErr.takeError());
}
- for (auto Object : Objects) {
- if (auto Err = handleFileConversionToGSYM(Object, OutFile))
+ for (StringRef Object : Objects)
+ if (Error Err = handleFileConversionToGSYM(Object, OutFile))
return Err;
- }
return Error::success();
}
diff --git a/src/llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp b/src/llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp
index 0d2744f..ed660bc 100644
--- a/src/llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp
@@ -54,9 +54,7 @@
using namespace llvm::opt;
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -69,13 +67,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
diff --git a/src/llvm-project/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp b/src/llvm-project/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
index eda165d..742f7b9 100644
--- a/src/llvm-project/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
@@ -99,7 +99,7 @@
TargetLibraryInfoImpl TLII(TM->getTargetTriple());
PM.add(new TargetLibraryInfoWrapperPass(TLII));
raw_null_ostream OS;
- TM->addPassesToEmitFile(PM, OS, nullptr, CGFT_Null);
+ TM->addPassesToEmitFile(PM, OS, nullptr, CodeGenFileType::Null);
PM.run(*M);
return 0;
@@ -129,33 +129,18 @@
exit(1);
}
- Triple TheTriple = Triple(Triple::normalize(TargetTriple));
-
- // Get the target specific parser.
- std::string Error;
- const Target *TheTarget =
- TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
- if (!TheTarget) {
- errs() << argv[0] << ": " << Error;
- return 1;
- }
-
// Set up the pipeline like llc does.
- std::string CPUStr = codegen::getCPUStr(),
- FeaturesStr = codegen::getFeaturesStr();
- CodeGenOpt::Level OLvl;
+ CodeGenOptLevel OLvl;
if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
OLvl = *Level;
} else {
errs() << argv[0] << ": invalid optimization level.\n";
return 1;
}
-
- TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple);
- TM.reset(TheTarget->createTargetMachine(
- TheTriple.getTriple(), CPUStr, FeaturesStr, Options,
- codegen::getExplicitRelocModel(), codegen::getExplicitCodeModel(), OLvl));
+ ExitOnError ExitOnErr(std::string(*argv[0]) + ": error:");
+ TM = ExitOnErr(codegen::createTargetMachineForTriple(
+ Triple::normalize(TargetTriple), OLvl));
assert(TM && "Could not allocate target machine!");
// Make sure we print the summary and the current unit when LLVM errors out.
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt
index a9f8bd1..c9d1d23 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt
@@ -11,6 +11,7 @@
JITLink
MC
Object
+ OrcDebugging
OrcJIT
OrcShared
OrcTargetProcess
@@ -27,12 +28,8 @@
llvm-jitlink-statistics.cpp
)
-if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
- target_link_libraries(llvm-jitlink PRIVATE network)
-endif()
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
- target_link_libraries(llvm-jitlink PRIVATE socket nsl)
-endif()
+ if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
+ target_link_libraries(llvm-jitlink PRIVATE socket)
+ endif()
export_executable_symbols(llvm-jitlink)
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp
index 415aee7..5271fdb 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp
@@ -108,32 +108,17 @@
if (Sym->getAddress() > LastSym->getAddress())
LastSym = Sym;
- if (isGOTSection) {
- if (Sym->isSymbolZeroFill())
- return make_error<StringError>("zero-fill atom in GOT section",
- inconvertibleErrorCode());
-
- // If this is a GOT symbol with size (i.e. not the GOT start symbol)
- // then add it to the GOT entry info table.
- if (Sym->getSize() != 0) {
- if (auto TS = getCOFFGOTTarget(G, Sym->getBlock()))
- FileInfo.GOTEntryInfos[TS->getName()] = {
- Sym->getSymbolContent(), Sym->getAddress().getValue()};
- else
- return TS.takeError();
+ if (isGOTSection || isStubsSection) {
+ if (isGOTSection) {
+ // Skip the GOT start symbol
+ if (Sym->getSize() != 0)
+ if (Error E = FileInfo.registerGOTEntry(G, *Sym, getCOFFGOTTarget))
+ return E;
+ } else {
+ if (Error E = FileInfo.registerStubEntry(G, *Sym, getCOFFStubTarget))
+ return E;
}
SectionContainsContent = true;
- } else if (isStubsSection) {
- if (Sym->isSymbolZeroFill())
- return make_error<StringError>("zero-fill atom in Stub section",
- inconvertibleErrorCode());
-
- if (auto TS = getCOFFStubTarget(G, Sym->getBlock()))
- FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue()};
- else
- return TS.takeError();
- SectionContainsContent = true;
}
if (Sym->hasName()) {
@@ -143,7 +128,8 @@
SectionContainsZeroFill = true;
} else {
S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue()};
+ Sym->getAddress().getValue(),
+ Sym->getTargetFlags()};
SectionContainsContent = true;
}
}
@@ -164,7 +150,7 @@
else
FileInfo.SectionInfos[Sec.getName()] = {
ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
- SecAddr.getValue()};
+ SecAddr.getValue(), FirstSym->getTargetFlags()};
}
return Error::success();
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
index 5200dbc..a8c804a 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
@@ -24,6 +24,10 @@
static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
+static bool isELFAArch32StubsSection(Section &S) {
+ return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");
+}
+
static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
auto EItr =
llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
@@ -55,7 +59,11 @@
if (!E)
return E.takeError();
auto &GOTSym = E->getTarget();
- if (!GOTSym.isDefined() || !isELFGOTSection(GOTSym.getBlock().getSection()))
+ if (!GOTSym.isDefined())
+ return make_error<StringError>("Stubs entry in " + G.getName() +
+ " does not point to GOT entry",
+ inconvertibleErrorCode());
+ if (!isELFGOTSection(GOTSym.getBlock().getSection()))
return make_error<StringError>(
"Stubs entry in " + G.getName() + ", \"" +
GOTSym.getBlock().getSection().getName() +
@@ -64,6 +72,32 @@
return getELFGOTTarget(G, GOTSym.getBlock());
}
+static Expected<Symbol &> getELFAArch32StubTarget(LinkGraph &G, Block &B) {
+ auto E = getFirstRelocationEdge(G, B);
+ if (!E)
+ return E.takeError();
+ return E->getTarget();
+}
+
+enum SectionType { GOT, Stubs, AArch32Stubs, Other };
+
+static Error registerSymbol(LinkGraph &G, Symbol &Sym, Session::FileInfo &FI,
+ SectionType SecType) {
+ switch (SecType) {
+ case GOT:
+ if (Sym.getSize() == 0)
+ return Error::success(); // Skip the GOT start symbol
+ return FI.registerGOTEntry(G, Sym, getELFGOTTarget);
+ case Stubs:
+ return FI.registerStubEntry(G, Sym, getELFStubTarget);
+ case AArch32Stubs:
+ return FI.registerMultiStubEntry(G, Sym, getELFAArch32StubTarget);
+ case Other:
+ return Error::success();
+ }
+ llvm_unreachable("Unhandled SectionType enum");
+}
+
namespace llvm {
Error registerELFGraphInfo(Session &S, LinkGraph &G) {
@@ -96,8 +130,16 @@
"\"",
inconvertibleErrorCode());
- bool isGOTSection = isELFGOTSection(Sec);
- bool isStubsSection = isELFStubsSection(Sec);
+ SectionType SecType;
+ if (isELFGOTSection(Sec)) {
+ SecType = GOT;
+ } else if (isELFStubsSection(Sec)) {
+ SecType = Stubs;
+ } else if (isELFAArch32StubsSection(Sec)) {
+ SecType = AArch32Stubs;
+ } else {
+ SecType = Other;
+ }
bool SectionContainsContent = false;
bool SectionContainsZeroFill = false;
@@ -110,31 +152,9 @@
if (Sym->getAddress() > LastSym->getAddress())
LastSym = Sym;
- if (isGOTSection) {
- if (Sym->isSymbolZeroFill())
- return make_error<StringError>("zero-fill atom in GOT section",
- inconvertibleErrorCode());
-
- // If this is a GOT symbol with size (i.e. not the GOT start symbol)
- // then add it to the GOT entry info table.
- if (Sym->getSize() != 0) {
- if (auto TS = getELFGOTTarget(G, Sym->getBlock()))
- FileInfo.GOTEntryInfos[TS->getName()] = {
- Sym->getSymbolContent(), Sym->getAddress().getValue()};
- else
- return TS.takeError();
- }
- SectionContainsContent = true;
- } else if (isStubsSection) {
- if (Sym->isSymbolZeroFill())
- return make_error<StringError>("zero-fill atom in Stub section",
- inconvertibleErrorCode());
-
- if (auto TS = getELFStubTarget(G, Sym->getBlock()))
- FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue()};
- else
- return TS.takeError();
+ if (SecType != Other) {
+ if (Error Err = registerSymbol(G, *Sym, FileInfo, SecType))
+ return Err;
SectionContainsContent = true;
}
@@ -145,7 +165,8 @@
SectionContainsZeroFill = true;
} else {
S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue()};
+ Sym->getAddress().getValue(),
+ Sym->getTargetFlags()};
SectionContainsContent = true;
}
}
@@ -170,7 +191,7 @@
else
FileInfo.SectionInfos[Sec.getName()] = {
ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
- SecAddr.getValue()};
+ SecAddr.getValue(), FirstSym->getTargetFlags()};
}
return Error::success();
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
index 7e4570c..f6d882d 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
@@ -11,12 +11,4 @@
intrinsics_gen
)
-if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
- target_link_libraries(llvm-jitlink-executor PRIVATE network)
-endif()
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
- target_link_libraries(llvm-jitlink-executor PRIVATE socket)
-endif()
-
export_executable_symbols(llvm-jitlink-executor)
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
index 71c83f2..c98bb26 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
@@ -54,9 +54,9 @@
errs() << "error: " << ErrMsg.str() << "\n\n"
<< "Usage:\n"
<< " llvm-jitlink-executor " << DebugOption
- << "filedescs=<infd>,<outfd> [args...]\n"
+ << "[test-jitloadergdb] filedescs=<infd>,<outfd> [args...]\n"
<< " llvm-jitlink-executor " << DebugOption
- << "listen=<host>:<port> [args...]\n";
+ << "[test-jitloadergdb] listen=<host>:<port> [args...]\n";
exit(1);
}
@@ -112,6 +112,21 @@
#endif // LLVM_ON_UNIX
}
+#if LLVM_ENABLE_THREADS
+
+// JITLink debug support plugins put information about JITed code in this GDB
+// JIT Interface global from OrcTargetProcess.
+extern "C" struct jit_descriptor __jit_debug_descriptor;
+
+static void *findLastDebugDescriptorEntryPtr() {
+ struct jit_code_entry *Last = __jit_debug_descriptor.first_entry;
+ while (Last && Last->next_entry)
+ Last = Last->next_entry;
+ return Last;
+}
+
+#endif
+
int main(int argc, char *argv[]) {
#if LLVM_ENABLE_THREADS
@@ -123,39 +138,46 @@
if (argc < 2)
printErrorAndExit("insufficient arguments");
- else {
- StringRef ConnectArg = argv[FirstProgramArg++];
+ StringRef NextArg = argv[FirstProgramArg++];
#ifndef NDEBUG
- if (ConnectArg == "debug") {
- DebugFlag = true;
- ConnectArg = argv[FirstProgramArg++];
- }
+ if (NextArg == "debug") {
+ DebugFlag = true;
+ NextArg = argv[FirstProgramArg++];
+ }
#endif
- StringRef SpecifierType, Specifier;
- std::tie(SpecifierType, Specifier) = ConnectArg.split('=');
- if (SpecifierType == "filedescs") {
- StringRef FD1Str, FD2Str;
- std::tie(FD1Str, FD2Str) = Specifier.split(',');
- if (FD1Str.getAsInteger(10, InFD))
- printErrorAndExit(FD1Str + " is not a valid file descriptor");
- if (FD2Str.getAsInteger(10, OutFD))
- printErrorAndExit(FD2Str + " is not a valid file descriptor");
- } else if (SpecifierType == "listen") {
- StringRef Host, PortStr;
- std::tie(Host, PortStr) = Specifier.split(':');
-
- int Port = 0;
- if (PortStr.getAsInteger(10, Port))
- printErrorAndExit("port number '" + PortStr +
- "' is not a valid integer");
-
- InFD = OutFD = openListener(Host.str(), PortStr.str());
- } else
- printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
+ std::vector<StringRef> TestOutputFlags;
+ while (NextArg.starts_with("test-")) {
+ TestOutputFlags.push_back(NextArg);
+ NextArg = argv[FirstProgramArg++];
}
+ if (llvm::is_contained(TestOutputFlags, "test-jitloadergdb"))
+ fprintf(stderr, "__jit_debug_descriptor.last_entry = 0x%016" PRIx64 "\n",
+ pointerToJITTargetAddress(findLastDebugDescriptorEntryPtr()));
+
+ StringRef SpecifierType, Specifier;
+ std::tie(SpecifierType, Specifier) = NextArg.split('=');
+ if (SpecifierType == "filedescs") {
+ StringRef FD1Str, FD2Str;
+ std::tie(FD1Str, FD2Str) = Specifier.split(',');
+ if (FD1Str.getAsInteger(10, InFD))
+ printErrorAndExit(FD1Str + " is not a valid file descriptor");
+ if (FD2Str.getAsInteger(10, OutFD))
+ printErrorAndExit(FD2Str + " is not a valid file descriptor");
+ } else if (SpecifierType == "listen") {
+ StringRef Host, PortStr;
+ std::tie(Host, PortStr) = Specifier.split(':');
+
+ int Port = 0;
+ if (PortStr.getAsInteger(10, Port))
+ printErrorAndExit("port number '" + PortStr + "' is not a valid integer");
+
+ InFD = OutFD = openListener(Host.str(), PortStr.str());
+ } else
+ printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
+
auto Server =
ExitOnErr(SimpleRemoteEPCServer::Create<FDSimpleRemoteEPCTransport>(
[](SimpleRemoteEPCServer::Setup &S) -> Error {
@@ -173,6 +195,11 @@
InFD, OutFD));
ExitOnErr(Server->waitForDisconnect());
+
+ if (llvm::is_contained(TestOutputFlags, "test-jitloadergdb"))
+ fprintf(stderr, "__jit_debug_descriptor.last_entry = 0x%016" PRIx64 "\n",
+ pointerToJITTargetAddress(findLastDebugDescriptorEntryPtr()));
+
return 0;
#else
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp
index bcb2f25..2c60c80 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-macho.cpp
@@ -111,27 +111,13 @@
FirstSym = Sym;
if (Sym->getAddress() > LastSym->getAddress())
LastSym = Sym;
- if (isGOTSection) {
- if (Sym->isSymbolZeroFill())
- return make_error<StringError>("zero-fill atom in GOT section",
- inconvertibleErrorCode());
-
- if (auto TS = getMachOGOTTarget(G, Sym->getBlock()))
- FileInfo.GOTEntryInfos[TS->getName()] = {
- Sym->getSymbolContent(), Sym->getAddress().getValue()};
- else
- return TS.takeError();
- SectionContainsContent = true;
- } else if (isStubsSection) {
- if (Sym->isSymbolZeroFill())
- return make_error<StringError>("zero-fill atom in Stub section",
- inconvertibleErrorCode());
-
- if (auto TS = getMachOStubTarget(G, Sym->getBlock()))
- FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue()};
- else
- return TS.takeError();
+ if (isGOTSection || isStubsSection) {
+ Error Err =
+ isGOTSection
+ ? FileInfo.registerGOTEntry(G, *Sym, getMachOGOTTarget)
+ : FileInfo.registerStubEntry(G, *Sym, getMachOStubTarget);
+ if (Err)
+ return Err;
SectionContainsContent = true;
} else if (Sym->hasName()) {
if (Sym->isSymbolZeroFill()) {
@@ -140,7 +126,8 @@
SectionContainsZeroFill = true;
} else {
S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
- Sym->getAddress().getValue()};
+ Sym->getAddress().getValue(),
+ Sym->getTargetFlags()};
SectionContainsContent = true;
}
}
@@ -160,7 +147,7 @@
else
FileInfo.SectionInfos[Sec.getName()] = {
ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
- SecAddr.getValue()};
+ SecAddr.getValue(), FirstSym->getTargetFlags()};
}
return Error::success();
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index 00dd520..769ed17 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -18,7 +18,9 @@
#include "llvm/ExecutionEngine/Orc/COFFPlatform.h"
#include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h"
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
-#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
@@ -30,6 +32,7 @@
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -55,7 +58,6 @@
#include <cstring>
#include <deque>
-#include <list>
#include <string>
#ifdef LLVM_ON_UNIX
@@ -140,6 +142,11 @@
cl::desc("Enable debugger suppport (default = !-noexec)"),
cl::init(true), cl::Hidden, cl::cat(JITLinkCategory));
+static cl::opt<bool> PerfSupport("perf-support",
+ cl::desc("Enable perf profiling support"),
+ cl::init(false), cl::Hidden,
+ cl::cat(JITLinkCategory));
+
static cl::opt<bool>
NoProcessSymbols("no-process-syms",
cl::desc("Do not resolve to llvm-jitlink process symbols"),
@@ -243,10 +250,14 @@
static ExitOnError ExitOnErr;
static LLVM_ATTRIBUTE_USED void linkComponents() {
- errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
- << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
- << (void *)&llvm_orc_registerJITLoaderGDBWrapper
- << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
+ errs() << "Linking in runtime functions\n"
+ << (void *)&llvm_orc_registerEHFrameSectionWrapper << '\n'
+ << (void *)&llvm_orc_deregisterEHFrameSectionWrapper << '\n'
+ << (void *)&llvm_orc_registerJITLoaderGDBWrapper << '\n'
+ << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n'
+ << (void *)&llvm_orc_registerJITLoaderPerfStart << '\n'
+ << (void *)&llvm_orc_registerJITLoaderPerfEnd << '\n'
+ << (void *)&llvm_orc_registerJITLoaderPerfImpl << '\n';
}
static bool UseTestResultOverride = false;
@@ -320,8 +331,12 @@
OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
for (auto &GOTKV : FI.GOTEntryInfos)
OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
- for (auto &StubKV : FI.StubInfos)
- OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
+ for (auto &StubKVs : FI.StubInfos) {
+ OS << " Stubs \"" << StubKVs.first() << "\":";
+ for (auto MemRegion : StubKVs.second)
+ OS << " " << MemRegion;
+ OS << "\n";
+ }
return OS;
}
@@ -501,7 +516,7 @@
auto FixedAI = std::move(AI);
FixedAI.MappingBase -= DeltaAddr;
for (auto &Seg : FixedAI.Segments)
- Seg.AG = {MemProt::Read | MemProt::Write, Seg.AG.getMemLifetimePolicy()};
+ Seg.AG = {MemProt::Read | MemProt::Write, Seg.AG.getMemLifetime()};
FixedAI.Actions.clear();
InProcessMemoryMapper::initialize(
FixedAI, [this, OnInitialized = std::move(OnInitialized)](
@@ -681,11 +696,12 @@
}
static Error loadProcessSymbols(Session &S) {
+ S.ProcessSymsJD = &S.ES.createBareJITDylib("Process");
auto FilterMainEntryPoint =
[EPName = S.ES.intern(EntryPointName)](SymbolStringPtr Name) {
return Name != EPName;
};
- S.MainJD->addGenerator(
+ S.ProcessSymsJD->addGenerator(
ExitOnErr(orc::EPCDynamicLibrarySearchGenerator::GetForTargetProcess(
S.ES, std::move(FilterMainEntryPoint))));
@@ -696,8 +712,9 @@
LLVM_DEBUG(dbgs() << "Loading dylibs...\n");
for (const auto &Dylib : Dylibs) {
LLVM_DEBUG(dbgs() << " " << Dylib << "\n");
- if (auto Err = S.loadAndLinkDynamicLibrary(*S.MainJD, Dylib))
- return Err;
+ auto DL = S.getOrLoadDynamicLibrary(Dylib);
+ if (!DL)
+ return DL.takeError();
}
return Error::success();
@@ -952,63 +969,79 @@
ES.setErrorReporter(reportLLVMJITLinkError);
- if (auto MainJDOrErr = ES.createJITDylib("main"))
- MainJD = &*MainJDOrErr;
- else {
- Err = MainJDOrErr.takeError();
- return;
- }
-
if (!NoProcessSymbols)
ExitOnErr(loadProcessSymbols(*this));
- else {
- // This symbol is used in testcases.
- auto &TestResultJD = ES.createBareJITDylib("<TestResultJD>");
- ExitOnErr(TestResultJD.define(absoluteSymbols(
- {{ES.intern("llvm_jitlink_setTestResultOverride"),
- {ExecutorAddr::fromPtr(llvm_jitlink_setTestResultOverride),
- JITSymbolFlags::Exported}}})));
- MainJD->addToLinkOrder(TestResultJD);
- }
ExitOnErr(loadDylibs(*this));
auto &TT = ES.getTargetTriple();
- if (DebuggerSupport && TT.isOSBinFormatMachO())
- ObjLayer.addPlugin(ExitOnErr(
- GDBJITDebugInfoRegistrationPlugin::Create(this->ES, *MainJD, TT)));
+ if (DebuggerSupport && TT.isOSBinFormatMachO()) {
+ if (!ProcessSymsJD) {
+ Err = make_error<StringError>("MachO debugging requires process symbols",
+ inconvertibleErrorCode());
+ return;
+ }
+ ObjLayer.addPlugin(ExitOnErr(GDBJITDebugInfoRegistrationPlugin::Create(
+ this->ES, *ProcessSymsJD, TT)));
+ }
+
+ if (PerfSupport && TT.isOSBinFormatELF()) {
+ if (!ProcessSymsJD) {
+ Err = make_error<StringError>("MachO debugging requires process symbols",
+ inconvertibleErrorCode());
+ return;
+ }
+ ObjLayer.addPlugin(ExitOnErr(DebugInfoPreservationPlugin::Create()));
+ ObjLayer.addPlugin(ExitOnErr(PerfSupportPlugin::Create(
+ this->ES.getExecutorProcessControl(), *ProcessSymsJD, true, true)));
+ }
// Set up the platform.
- if (TT.isOSBinFormatMachO() && !OrcRuntime.empty()) {
- if (auto P =
- MachOPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str()))
- ES.setPlatform(std::move(*P));
- else {
- Err = P.takeError();
- return;
- }
- } else if (TT.isOSBinFormatELF() && !OrcRuntime.empty()) {
- if (auto P =
- ELFNixPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str()))
- ES.setPlatform(std::move(*P));
- else {
- Err = P.takeError();
- return;
- }
- } else if (TT.isOSBinFormatCOFF() && !OrcRuntime.empty()) {
- auto LoadDynLibrary = [&, this](JITDylib &JD, StringRef DLLName) -> Error {
- if (!DLLName.ends_with_insensitive(".dll"))
- return make_error<StringError>("DLLName not ending with .dll",
- inconvertibleErrorCode());
- return loadAndLinkDynamicLibrary(JD, DLLName);
- };
+ if (!OrcRuntime.empty()) {
+ assert(ProcessSymsJD && "ProcessSymsJD should have been set");
+ PlatformJD = &ES.createBareJITDylib("Platform");
+ PlatformJD->addToLinkOrder(*ProcessSymsJD);
- if (auto P = COFFPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str(),
- std::move(LoadDynLibrary)))
- ES.setPlatform(std::move(*P));
- else {
- Err = P.takeError();
+ if (TT.isOSBinFormatMachO()) {
+ if (auto P = MachOPlatform::Create(ES, ObjLayer, *PlatformJD,
+ OrcRuntime.c_str()))
+ ES.setPlatform(std::move(*P));
+ else {
+ Err = P.takeError();
+ return;
+ }
+ } else if (TT.isOSBinFormatELF()) {
+ if (auto P = ELFNixPlatform::Create(ES, ObjLayer, *PlatformJD,
+ OrcRuntime.c_str()))
+ ES.setPlatform(std::move(*P));
+ else {
+ Err = P.takeError();
+ return;
+ }
+ } else if (TT.isOSBinFormatCOFF()) {
+ auto LoadDynLibrary = [&, this](JITDylib &JD,
+ StringRef DLLName) -> Error {
+ if (!DLLName.ends_with_insensitive(".dll"))
+ return make_error<StringError>("DLLName not ending with .dll",
+ inconvertibleErrorCode());
+ return loadAndLinkDynamicLibrary(JD, DLLName);
+ };
+
+ if (auto P = COFFPlatform::Create(ES, ObjLayer, *PlatformJD,
+ OrcRuntime.c_str(),
+ std::move(LoadDynLibrary)))
+ ES.setPlatform(std::move(*P));
+ else {
+ Err = P.takeError();
+ return;
+ }
+ } else {
+ Err = make_error<StringError>(
+ "-" + OrcRuntime.ArgStr + " specified, but format " +
+ Triple::getObjectFormatTypeName(TT.getObjectFormat()) +
+ " not supported",
+ inconvertibleErrorCode());
return;
}
} else if (TT.isOSBinFormatELF()) {
@@ -1020,6 +1053,24 @@
ES, ExitOnErr(createJITLoaderGDBRegistrar(this->ES)), true, true));
}
+ if (auto MainJDOrErr = ES.createJITDylib("main"))
+ MainJD = &*MainJDOrErr;
+ else {
+ Err = MainJDOrErr.takeError();
+ return;
+ }
+
+ if (NoProcessSymbols) {
+ // This symbol is used in testcases, but we're not reflecting process
+ // symbols so we'll need to make it available some other way.
+ auto &TestResultJD = ES.createBareJITDylib("<TestResultJD>");
+ ExitOnErr(TestResultJD.define(absoluteSymbols(
+ {{ES.intern("llvm_jitlink_setTestResultOverride"),
+ {ExecutorAddr::fromPtr(llvm_jitlink_setTestResultOverride),
+ JITSymbolFlags::Exported}}})));
+ MainJD->addToLinkOrder(TestResultJD);
+ }
+
ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
// Process any harness files.
@@ -1136,6 +1187,62 @@
return Error::success();
}
+Error Session::FileInfo::registerGOTEntry(
+ LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) {
+ if (Sym.isSymbolZeroFill())
+ return make_error<StringError>("Unexpected zero-fill symbol in section " +
+ Sym.getBlock().getSection().getName(),
+ inconvertibleErrorCode());
+ auto TS = GetSymbolTarget(G, Sym.getBlock());
+ if (!TS)
+ return TS.takeError();
+ GOTEntryInfos[TS->getName()] = {Sym.getSymbolContent(),
+ Sym.getAddress().getValue(),
+ Sym.getTargetFlags()};
+ return Error::success();
+}
+
+Error Session::FileInfo::registerStubEntry(
+ LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) {
+ if (Sym.isSymbolZeroFill())
+ return make_error<StringError>("Unexpected zero-fill symbol in section " +
+ Sym.getBlock().getSection().getName(),
+ inconvertibleErrorCode());
+ auto TS = GetSymbolTarget(G, Sym.getBlock());
+ if (!TS)
+ return TS.takeError();
+
+ SmallVectorImpl<MemoryRegionInfo> &Entry = StubInfos[TS->getName()];
+ Entry.insert(Entry.begin(),
+ {Sym.getSymbolContent(), Sym.getAddress().getValue(),
+ Sym.getTargetFlags()});
+ return Error::success();
+}
+
+Error Session::FileInfo::registerMultiStubEntry(
+ LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) {
+ if (Sym.isSymbolZeroFill())
+ return make_error<StringError>("Unexpected zero-fill symbol in section " +
+ Sym.getBlock().getSection().getName(),
+ inconvertibleErrorCode());
+
+ auto Target = GetSymbolTarget(G, Sym.getBlock());
+ if (!Target)
+ return Target.takeError();
+
+ SmallVectorImpl<MemoryRegionInfo> &Entry = StubInfos[Target->getName()];
+ Entry.emplace_back(Sym.getSymbolContent(), Sym.getAddress().getValue(),
+ Sym.getTargetFlags());
+
+ // Let's keep stubs ordered by ascending address.
+ std::sort(Entry.begin(), Entry.end(),
+ [](const MemoryRegionInfo &L, const MemoryRegionInfo &R) {
+ return L.getTargetAddress() < R.getTargetAddress();
+ });
+
+ return Error::success();
+}
+
Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) {
auto FileInfoItr = FileInfos.find(FileName);
if (FileInfoItr == FileInfos.end())
@@ -1158,8 +1265,59 @@
return SecInfoItr->second;
}
+class MemoryMatcher {
+public:
+ MemoryMatcher(ArrayRef<char> Content)
+ : Pos(Content.data()), End(Pos + Content.size()) {}
+
+ template <typename MaskType> bool matchMask(MaskType Mask) {
+ if (Mask == (Mask & *reinterpret_cast<const MaskType *>(Pos))) {
+ Pos += sizeof(MaskType);
+ return true;
+ }
+ return false;
+ }
+
+ template <typename ValueType> bool matchEqual(ValueType Value) {
+ if (Value == *reinterpret_cast<const ValueType *>(Pos)) {
+ Pos += sizeof(ValueType);
+ return true;
+ }
+ return false;
+ }
+
+ bool done() const { return Pos == End; }
+
+private:
+ const char *Pos;
+ const char *End;
+};
+
+static StringRef detectStubKind(const Session::MemoryRegionInfo &Stub) {
+ using namespace support::endian;
+ auto Armv7MovWTle = byte_swap<uint32_t, endianness::little>(0xe300c000);
+ auto Armv7BxR12le = byte_swap<uint32_t, endianness::little>(0xe12fff1c);
+ auto Thumbv7MovWTle = byte_swap<uint32_t, endianness::little>(0x0c00f240);
+ auto Thumbv7BxR12le = byte_swap<uint16_t, endianness::little>(0x4760);
+
+ MemoryMatcher M(Stub.getContent());
+ if (M.matchMask(Thumbv7MovWTle)) {
+ if (M.matchMask(Thumbv7MovWTle))
+ if (M.matchEqual(Thumbv7BxR12le))
+ if (M.done())
+ return "thumbv7_abs_le";
+ } else if (M.matchMask(Armv7MovWTle)) {
+ if (M.matchMask(Armv7MovWTle))
+ if (M.matchEqual(Armv7BxR12le))
+ if (M.done())
+ return "armv7_abs_le";
+ }
+ return "";
+}
+
Expected<Session::MemoryRegionInfo &>
-Session::findStubInfo(StringRef FileName, StringRef TargetName) {
+Session::findStubInfo(StringRef FileName, StringRef TargetName,
+ StringRef KindNameFilter) {
auto FI = findFileInfo(FileName);
if (!FI)
return FI.takeError();
@@ -1169,7 +1327,38 @@
"\" registered for file \"" + FileName +
"\"",
inconvertibleErrorCode());
- return StubInfoItr->second;
+ auto &StubsForTarget = StubInfoItr->second;
+ assert(!StubsForTarget.empty() && "At least 1 stub in each entry");
+ if (KindNameFilter.empty() && StubsForTarget.size() == 1)
+ return StubsForTarget[0]; // Regular single-stub match
+
+ std::string KindsStr;
+ SmallVector<MemoryRegionInfo *, 1> Matches;
+ Regex KindNameMatcher(KindNameFilter.empty() ? ".*" : KindNameFilter);
+ for (MemoryRegionInfo &Stub : StubsForTarget) {
+ StringRef Kind = detectStubKind(Stub);
+ if (KindNameMatcher.match(Kind))
+ Matches.push_back(&Stub);
+ KindsStr += "\"" + (Kind.empty() ? "<unknown>" : Kind.str()) + "\", ";
+ }
+ if (Matches.empty())
+ return make_error<StringError>(
+ "\"" + TargetName + "\" has " + Twine(StubsForTarget.size()) +
+ " stubs in file \"" + FileName +
+ "\", but none of them matches the stub-kind filter \"" +
+ KindNameFilter + "\" (all encountered kinds are " +
+ StringRef(KindsStr.data(), KindsStr.size() - 2) + ").",
+ inconvertibleErrorCode());
+ if (Matches.size() > 1)
+ return make_error<StringError>(
+ "\"" + TargetName + "\" has " + Twine(Matches.size()) +
+ " candidate stubs in file \"" + FileName +
+ "\". Please refine stub-kind filter \"" + KindNameFilter +
+ "\" for disambiguation (encountered kinds are " +
+ StringRef(KindsStr.data(), KindsStr.size() - 2) + ").",
+ inconvertibleErrorCode());
+
+ return *Matches[0];
}
Expected<Session::MemoryRegionInfo &>
@@ -1249,6 +1438,10 @@
if (DebuggerSupport.getNumOccurrences() == 0 && NoExec)
DebuggerSupport = false;
+ if (!OrcRuntime.empty() && NoProcessSymbols)
+ return make_error<StringError>("-orc-runtime requires process symbols",
+ inconvertibleErrorCode());
+
// If -slab-allocate is passed, check that we're not trying to use it in
// -oop-executor or -oop-executor-connect mode.
//
@@ -1348,6 +1541,13 @@
}
}
+ if (S.PlatformJD)
+ S.JDSearchOrder.push_back(
+ {S.PlatformJD, JITDylibLookupFlags::MatchExportedSymbolsOnly});
+ if (S.ProcessSymsJD)
+ S.JDSearchOrder.push_back(
+ {S.ProcessSymsJD, JITDylibLookupFlags::MatchExportedSymbolsOnly});
+
LLVM_DEBUG({
dbgs() << "Dylib search order is [ ";
for (auto &KV : S.JDSearchOrder)
@@ -1388,7 +1588,8 @@
return Err;
// Register the absolute symbol with the session symbol infos.
- S.SymbolInfos[Name] = {ArrayRef<char>(), Addr};
+ S.SymbolInfos[Name] = {ArrayRef<char>(), Addr,
+ AbsDef.getFlags().getTargetFlags()};
}
return Error::success();
@@ -1398,23 +1599,67 @@
const std::map<unsigned, JITDylib *> &IdxToJD) {
// Define absolute symbols.
LLVM_DEBUG(dbgs() << "Defining aliases...\n");
+
+ DenseMap<std::pair<JITDylib *, JITDylib *>, SymbolAliasMap> Reexports;
for (auto AliasItr = Aliases.begin(), AliasEnd = Aliases.end();
AliasItr != AliasEnd; ++AliasItr) {
- unsigned AliasArgIdx = Aliases.getPosition(AliasItr - Aliases.begin());
- auto &JD = *std::prev(IdxToJD.lower_bound(AliasArgIdx))->second;
- StringRef AliasStmt = *AliasItr;
- size_t EqIdx = AliasStmt.find_first_of('=');
- if (EqIdx == StringRef::npos)
- return make_error<StringError>("Invalid alias definition \"" + AliasStmt +
- "\". Syntax: <name>=<addr>",
- inconvertibleErrorCode());
- StringRef Alias = AliasStmt.substr(0, EqIdx).trim();
- StringRef Aliasee = AliasStmt.substr(EqIdx + 1).trim();
+ auto BadExpr = [&]() {
+ return make_error<StringError>(
+ "Invalid alias definition \"" + *AliasItr +
+ "\". Syntax: [<dst-jd>:]<alias>=[<src-jd>:]<aliasee>",
+ inconvertibleErrorCode());
+ };
- SymbolAliasMap SAM;
- SAM[S.ES.intern(Alias)] = {S.ES.intern(Aliasee), JITSymbolFlags::Exported};
- if (auto Err = JD.define(symbolAliases(std::move(SAM))))
+ auto GetJD = [&](StringRef JDName) -> Expected<JITDylib *> {
+ if (JDName.empty()) {
+ unsigned AliasArgIdx = Aliases.getPosition(AliasItr - Aliases.begin());
+ return std::prev(IdxToJD.lower_bound(AliasArgIdx))->second;
+ }
+
+ auto *JD = S.ES.getJITDylibByName(JDName);
+ if (!JD)
+ return make_error<StringError>(StringRef("In alias definition \"") +
+ *AliasItr + "\" no dylib named " +
+ JDName,
+ inconvertibleErrorCode());
+
+ return JD;
+ };
+
+ {
+ // First split on '=' to get alias and aliasee.
+ StringRef AliasStmt = *AliasItr;
+ auto [AliasExpr, AliaseeExpr] = AliasStmt.split('=');
+ if (AliaseeExpr.empty())
+ return BadExpr();
+
+ auto [AliasJDName, Alias] = AliasExpr.split(':');
+ if (Alias.empty())
+ std::swap(AliasJDName, Alias);
+
+ auto AliasJD = GetJD(AliasJDName);
+ if (!AliasJD)
+ return AliasJD.takeError();
+
+ auto [AliaseeJDName, Aliasee] = AliaseeExpr.split(':');
+ if (Aliasee.empty())
+ std::swap(AliaseeJDName, Aliasee);
+
+ if (AliaseeJDName.empty() && !AliasJDName.empty())
+ AliaseeJDName = AliasJDName;
+ auto AliaseeJD = GetJD(AliaseeJDName);
+ if (!AliaseeJD)
+ return AliaseeJD.takeError();
+
+ Reexports[{*AliasJD, *AliaseeJD}][S.ES.intern(Alias)] = {
+ S.ES.intern(Aliasee), JITSymbolFlags::Exported};
+ }
+ }
+
+ for (auto &[JDs, AliasMap] : Reexports) {
+ auto [DstJD, SrcJD] = JDs;
+ if (auto Err = DstJD->define(reexports(*SrcJD, std::move(AliasMap))))
return Err;
}
@@ -1444,8 +1689,8 @@
unsigned InputFileArgIdx =
InputFiles.getPosition(InputFileItr - InputFiles.begin());
const std::string &InputFile = *InputFileItr;
- if (StringRef(InputFile).endswith(".a") ||
- StringRef(InputFile).endswith(".lib"))
+ if (StringRef(InputFile).ends_with(".a") ||
+ StringRef(InputFile).ends_with(".lib"))
continue;
auto &JD = *std::prev(IdxToJD.lower_bound(InputFileArgIdx))->second;
LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
@@ -1545,7 +1790,7 @@
for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
InputFileItr != InputFileEnd; ++InputFileItr) {
StringRef InputFile = *InputFileItr;
- if (!InputFile.endswith(".a") && !InputFile.endswith(".lib"))
+ if (!InputFile.ends_with(".a") && !InputFile.ends_with(".lib"))
continue;
LibraryLoad LL;
LL.LibName = InputFile.str();
@@ -1748,6 +1993,14 @@
inconvertibleErrorCode());
}
+ // Add platform and process symbols if available.
+ for (auto &[Idx, JD] : IdxToJD) {
+ if (S.PlatformJD)
+ JD->addToLinkOrder(*S.PlatformJD);
+ if (S.ProcessSymsJD)
+ JD->addToLinkOrder(*S.ProcessSymsJD);
+ }
+
return Error::success();
}
@@ -1856,15 +2109,12 @@
std::move(MAI), std::move(Ctx), std::move(Disassembler),
std::move(MII), std::move(MIA), std::move(InstPrinter)};
}
-
-static Error runChecks(Session &S) {
+static Error runChecks(Session &S, Triple TT, SubtargetFeatures Features) {
if (CheckFiles.empty())
return Error::success();
LLVM_DEBUG(dbgs() << "Running checks...\n");
- auto TI = getTargetInfo(S.ES.getTargetTriple(), S.Features);
-
auto IsSymbolValid = [&S](StringRef Symbol) {
return S.isSymbolRegistered(Symbol);
};
@@ -1877,8 +2127,9 @@
return S.findSectionInfo(FileName, SectionName);
};
- auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
- return S.findStubInfo(FileName, SectionName);
+ auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName,
+ StringRef KindNameFilter) {
+ return S.findStubInfo(FileName, SectionName, KindNameFilter);
};
auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
@@ -1887,8 +2138,9 @@
RuntimeDyldChecker Checker(
IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
- S.ES.getTargetTriple().isLittleEndian() ? support::little : support::big,
- TI.Disassembler.get(), TI.InstPrinter.get(), dbgs());
+ S.ES.getTargetTriple().isLittleEndian() ? llvm::endianness::little
+ : llvm::endianness::big,
+ TT, StringRef(), Features, dbgs());
std::string CheckLineStart = "# " + CheckName + ":";
for (auto &CheckFile : CheckFiles) {
@@ -2000,7 +2252,7 @@
auto [TT, Features] = getFirstFileTripleAndFeatures();
ExitOnErr(sanitizeArguments(TT, argv[0]));
- auto S = ExitOnErr(Session::Create(std::move(TT), std::move(Features)));
+ auto S = ExitOnErr(Session::Create(TT, Features));
enableStatistics(*S, !OrcRuntime.empty());
@@ -2036,7 +2288,7 @@
exit(1);
}
- ExitOnErr(runChecks(*S));
+ ExitOnErr(runChecks(*S, std::move(TT), std::move(Features)));
int Result = 0;
if (!NoExec) {
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.h b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.h
index 9389be4..e09c15a 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.h
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.h
@@ -25,14 +25,14 @@
#include "llvm/TargetParser/SubtargetFeature.h"
#include "llvm/TargetParser/Triple.h"
-#include <vector>
-
namespace llvm {
struct Session {
orc::ExecutionSession ES;
orc::JITDylib *MainJD = nullptr;
+ orc::JITDylib *ProcessSymsJD = nullptr;
+ orc::JITDylib *PlatformJD = nullptr;
orc::ObjectLinkingLayer ObjLayer;
orc::JITDylibSearchOrder JDSearchOrder;
SubtargetFeatures Features;
@@ -49,8 +49,20 @@
struct FileInfo {
StringMap<MemoryRegionInfo> SectionInfos;
- StringMap<MemoryRegionInfo> StubInfos;
+ StringMap<SmallVector<MemoryRegionInfo, 1>> StubInfos;
StringMap<MemoryRegionInfo> GOTEntryInfos;
+
+ using Symbol = jitlink::Symbol;
+ using LinkGraph = jitlink::LinkGraph;
+ using GetSymbolTargetFunction =
+ unique_function<Expected<Symbol &>(LinkGraph &G, jitlink::Block &)>;
+
+ Error registerGOTEntry(LinkGraph &G, Symbol &Sym,
+ GetSymbolTargetFunction GetSymbolTarget);
+ Error registerStubEntry(LinkGraph &G, Symbol &Sym,
+ GetSymbolTargetFunction GetSymbolTarget);
+ Error registerMultiStubEntry(LinkGraph &G, Symbol &Sym,
+ GetSymbolTargetFunction GetSymbolTarget);
};
using DynLibJDMap = std::map<std::string, orc::JITDylib *>;
@@ -64,7 +76,8 @@
Expected<MemoryRegionInfo &> findSectionInfo(StringRef FileName,
StringRef SectionName);
Expected<MemoryRegionInfo &> findStubInfo(StringRef FileName,
- StringRef TargetName);
+ StringRef TargetName,
+ StringRef KindNameFilter);
Expected<MemoryRegionInfo &> findGOTEntryInfo(StringRef FileName,
StringRef TargetName);
diff --git a/src/llvm-project/llvm/tools/llvm-libtool-darwin/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-libtool-darwin/CMakeLists.txt
index bc4b31f..eb95a5f 100644
--- a/src/llvm-project/llvm/tools/llvm-libtool-darwin/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-libtool-darwin/CMakeLists.txt
@@ -18,6 +18,7 @@
DEPENDS
LibtoolDarwinOptsTableGen
+ GENERATE_DRIVER
)
if(LLVM_INSTALL_CCTOOLS_SYMLINKS)
diff --git a/src/llvm-project/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp b/src/llvm-project/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
index 9188cad..77ae9b4 100644
--- a/src/llvm-project/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
+++ b/src/llvm-project/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
@@ -23,7 +23,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -31,6 +31,7 @@
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TextAPI/Architecture.h"
+#include <cstdlib>
#include <map>
#include <type_traits>
@@ -42,9 +43,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -57,13 +56,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -138,7 +131,7 @@
static Error processCommandLineLibraries() {
for (StringRef BaseName : Libraries) {
Expected<std::string> FullPath = searchForFile(
- BaseName.endswith(".o") ? BaseName.str() : "lib" + BaseName + ".a");
+ BaseName.ends_with(".o") ? BaseName.str() : "lib" + BaseName + ".a");
if (!FullPath)
return FullPath.takeError();
InputFiles.push_back(FullPath.get());
@@ -600,18 +593,17 @@
if (NewMembers.size() == 1)
return writeArchive(OutputFile, NewMembers.begin()->second.getMembers(),
- /*WriteSymtab=*/true,
+ SymtabWritingMode::NormalSymtab,
/*Kind=*/object::Archive::K_DARWIN, C.Deterministic,
/*Thin=*/false);
SmallVector<OwningBinary<Archive>, 2> OutputBinaries;
for (const std::pair<const uint64_t, NewArchiveMemberList> &M : NewMembers) {
Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
- writeArchiveToBuffer(M.second.getMembers(),
- /*WriteSymtab=*/true,
- /*Kind=*/object::Archive::K_DARWIN,
- C.Deterministic,
- /*Thin=*/false);
+ writeArchiveToBuffer(
+ M.second.getMembers(), SymtabWritingMode::NormalSymtab,
+ /*Kind=*/object::Archive::K_DARWIN, C.Deterministic,
+ /*Thin=*/false);
if (!OutputBufferOrErr)
return OutputBufferOrErr.takeError();
std::unique_ptr<MemoryBuffer> &OutputBuffer = OutputBufferOrErr.get();
@@ -733,8 +725,7 @@
return C;
}
-int main(int Argc, char **Argv) {
- InitLLVM X(Argc, Argv);
+int llvm_libtool_darwin_main(int Argc, char **Argv, const llvm::ToolContext &) {
Expected<Config> ConfigOrErr = parseCommandLine(Argc, Argv);
if (!ConfigOrErr) {
WithColor::defaultErrorHandler(ConfigOrErr.takeError());
@@ -760,4 +751,5 @@
}
break;
}
+ return EXIT_SUCCESS;
}
diff --git a/src/llvm-project/llvm/tools/llvm-link/llvm-link.cpp b/src/llvm-project/llvm/tools/llvm-link/llvm-link.cpp
index 32ab9fa..a476b50 100644
--- a/src/llvm-project/llvm/tools/llvm-link/llvm-link.cpp
+++ b/src/llvm-project/llvm/tools/llvm-link/llvm-link.cpp
@@ -323,6 +323,11 @@
};
ModuleLazyLoaderCache ModuleLoaderCache(ModuleLoader);
+ // Owns the filename strings used to key into the ImportList. Normally this is
+ // constructed from the index and the strings are owned by the index, however,
+ // since we are synthesizing this data structure from options we need a cache
+ // to own those strings.
+ StringSet<> FileNameStringCache;
for (const auto &Import : Imports) {
// Identify the requested function and its bitcode source file.
size_t Idx = Import.find(':');
@@ -360,7 +365,8 @@
if (Verbose)
errs() << "Importing " << FunctionName << " from " << FileName << "\n";
- auto &Entry = ImportList[FileName];
+ auto &Entry =
+ ImportList[FileNameStringCache.insert(FileName).first->getKey()];
Entry.insert(F->getGUID());
}
auto CachedModuleLoader = [&](StringRef Identifier) {
diff --git a/src/llvm-project/llvm/tools/llvm-lipo/LipoOpts.td b/src/llvm-project/llvm/tools/llvm-lipo/LipoOpts.td
index 8663535..32bdca4 100644
--- a/src/llvm-project/llvm/tools/llvm-lipo/LipoOpts.td
+++ b/src/llvm-project/llvm/tools/llvm-lipo/LipoOpts.td
@@ -58,3 +58,6 @@
def output : Option<["-", "--"], "output", KIND_SEPARATE>,
HelpText<"Create output file with specified name">;
def o : JoinedOrSeparate<["-"], "o">, Alias<output>;
+
+def fat64 : Option<["-", "--"], "fat64", KIND_FLAG>,
+ HelpText<"Use 64 bits Universal Mach-O format">;
diff --git a/src/llvm-project/llvm/tools/llvm-lipo/llvm-lipo.cpp b/src/llvm-project/llvm/tools/llvm-lipo/llvm-lipo.cpp
index d37df62..083a922 100644
--- a/src/llvm-project/llvm/tools/llvm-lipo/llvm-lipo.cpp
+++ b/src/llvm-project/llvm/tools/llvm-lipo/llvm-lipo.cpp
@@ -26,7 +26,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/WithColor.h"
@@ -67,9 +66,7 @@
namespace {
enum LipoID {
LIPO_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- LIPO_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),
#include "LipoOpts.inc"
#undef OPTION
};
@@ -82,13 +79,9 @@
#include "LipoOpts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info LipoInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, \
- METAVAR, LIPO_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, LIPO_##GROUP, \
- LIPO_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),
#include "LipoOpts.inc"
#undef OPTION
};
@@ -122,6 +115,7 @@
std::string ArchType;
std::string OutputFile;
LipoAction ActionToPerform;
+ bool UseFat64;
};
static Slice createSliceFromArchive(LLVMContext &LLVMCtx, const Archive &A) {
@@ -229,6 +223,8 @@
Twine(AlignmentValue));
}
+ C.UseFat64 = InputArgs.hasArg(LIPO_fat64);
+
SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));
if (ActionArgs.empty())
reportError("at least one action should be specified");
@@ -602,9 +598,11 @@
return Slices;
}
-[[noreturn]] static void createUniversalBinary(
- LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries,
- const StringMap<const uint32_t> &Alignments, StringRef OutputFileName) {
+[[noreturn]] static void
+createUniversalBinary(LLVMContext &LLVMCtx,
+ ArrayRef<OwningBinary<Binary>> InputBinaries,
+ const StringMap<const uint32_t> &Alignments,
+ StringRef OutputFileName, FatHeaderType HeaderType) {
assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries");
assert(!OutputFileName.empty() && "Create expects a single output file");
@@ -615,7 +613,7 @@
checkUnusedAlignments(Slices, Alignments);
llvm::stable_sort(Slices);
- if (Error E = writeUniversalBinary(Slices, OutputFileName))
+ if (Error E = writeUniversalBinary(Slices, OutputFileName, HeaderType))
reportError(std::move(E));
exit(EXIT_SUCCESS);
@@ -725,7 +723,6 @@
}
int llvm_lipo_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
@@ -753,8 +750,9 @@
C.OutputFile);
break;
case LipoAction::CreateUniversal:
- createUniversalBinary(LLVMCtx, InputBinaries, C.SegmentAlignments,
- C.OutputFile);
+ createUniversalBinary(
+ LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile,
+ C.UseFat64 ? FatHeaderType::Fat64Header : FatHeaderType::FatHeader);
break;
case LipoAction::ReplaceArch:
replaceSlices(LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile,
diff --git a/src/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp b/src/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp
index 51921d4..735b376 100644
--- a/src/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp
+++ b/src/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp
@@ -52,7 +52,6 @@
#include <cassert>
#include <cstdint>
#include <cstdlib>
-#include <list>
#include <map>
#include <memory>
#include <string>
@@ -481,12 +480,11 @@
/// currently available via the gold plugin via -thinlto.
static void createCombinedModuleSummaryIndex() {
ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);
- uint64_t NextModuleId = 0;
for (auto &Filename : InputFilenames) {
ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
std::unique_ptr<MemoryBuffer> MB =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
- ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex, NextModuleId++));
+ ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex));
}
// In order to use this index for testing, specifically import testing, we
// need to update any indirect call edges created from SamplePGO, so that they
@@ -528,7 +526,7 @@
if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
error(EC, "error creating the directory '" + ParentPath + "'");
}
- return std::string(NewPath.str());
+ return std::string(NewPath);
}
namespace thinlto {
diff --git a/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp b/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp
index 7456a2f..a588058 100644
--- a/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp
@@ -31,10 +31,8 @@
typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>
ByteArrayTy;
-static bool PrintInsts(const MCDisassembler &DisAsm,
- const ByteArrayTy &Bytes,
- SourceMgr &SM, raw_ostream &Out,
- MCStreamer &Streamer, bool InAtomicBlock,
+static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
+ SourceMgr &SM, MCStreamer &Streamer, bool InAtomicBlock,
const MCSubtargetInfo &STI) {
ArrayRef<uint8_t> Data(Bytes.first.data(), Bytes.first.size());
@@ -132,7 +130,7 @@
int Disassembler::disassemble(const Target &T, const std::string &Triple,
MCSubtargetInfo &STI, MCStreamer &Streamer,
MemoryBuffer &Buffer, SourceMgr &SM,
- MCContext &Ctx, raw_ostream &Out,
+ MCContext &Ctx,
const MCTargetOptions &MCOptions) {
std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
@@ -193,8 +191,8 @@
ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
if (!ByteArray.first.empty())
- ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer,
- InAtomicBlock, STI);
+ ErrorOccurred |=
+ PrintInsts(*DisAsm, ByteArray, SM, Streamer, InAtomicBlock, STI);
}
if (InAtomicBlock) {
diff --git a/src/llvm-project/llvm/tools/llvm-mc/Disassembler.h b/src/llvm-project/llvm/tools/llvm-mc/Disassembler.h
index a1603e5..d0226ab 100644
--- a/src/llvm-project/llvm/tools/llvm-mc/Disassembler.h
+++ b/src/llvm-project/llvm/tools/llvm-mc/Disassembler.h
@@ -32,7 +32,7 @@
static int disassemble(const Target &T, const std::string &Triple,
MCSubtargetInfo &STI, MCStreamer &Streamer,
MemoryBuffer &Buffer, SourceMgr &SM, MCContext &Ctx,
- raw_ostream &Out, const MCTargetOptions &MCOptions);
+ const MCTargetOptions &MCOptions);
};
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp b/src/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp
index 572723a..cf6aaa1 100644
--- a/src/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -216,6 +216,7 @@
AC_Assemble,
AC_Disassemble,
AC_MDisassemble,
+ AC_CDisassemble,
};
static cl::opt<ActionType> Action(
@@ -226,7 +227,9 @@
clEnumValN(AC_Disassemble, "disassemble",
"Disassemble strings of hex bytes"),
clEnumValN(AC_MDisassemble, "mdis",
- "Marked up disassembly of strings of hex bytes")),
+ "Marked up disassembly of strings of hex bytes"),
+ clEnumValN(AC_CDisassemble, "cdis",
+ "Colored disassembly of strings of hex bytes")),
cl::cat(MCCategory));
static const Target *GetTarget(const char *ProgName) {
@@ -544,6 +547,11 @@
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
auto FOut = std::make_unique<formatted_raw_ostream>(*OS);
+ // FIXME: Workaround for bug in formatted_raw_ostream. Color escape codes
+ // are (incorrectly) written directly to the unbuffered raw_ostream wrapped
+ // by the formatted_raw_ostream.
+ if (Action == AC_CDisassemble)
+ FOut->SetUnbuffered();
Str.reset(
TheTarget->createAsmStreamer(Ctx, std::move(FOut), /*asmverbose*/ true,
/*useDwarfDirectory*/ true, IP,
@@ -586,17 +594,20 @@
*MCII, MCOptions);
break;
case AC_MDisassemble:
- assert(IP && "Expected assembly output");
IP->setUseMarkup(true);
disassemble = true;
break;
+ case AC_CDisassemble:
+ IP->setUseColor(true);
+ disassemble = true;
+ break;
case AC_Disassemble:
disassemble = true;
break;
}
if (disassemble)
Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer,
- SrcMgr, Ctx, Out->os(), MCOptions);
+ SrcMgr, Ctx, MCOptions);
// Keep output if no errors.
if (Res == 0) {
diff --git a/src/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp b/src/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
index b254ccd..b702113 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
@@ -611,9 +611,9 @@
ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution();
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
for (unsigned I = 0, E = Distribution.size(); I < E; ++I) {
- unsigned ResourceCycles = Distribution[I];
- if (ResourceCycles) {
- double Frequency = (double)ResourceCycles * 100 / TotalCycles;
+ unsigned ReleaseAtCycles = Distribution[I];
+ if (ReleaseAtCycles) {
+ double Frequency = (double)ReleaseAtCycles * 100 / TotalCycles;
const MCProcResourceDesc &PRDesc = *SM.getProcResource(I);
OS << "\n - " << PRDesc.Name << " [ "
<< format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";
diff --git a/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp b/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
index 0f059bcc..f39350f 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
@@ -54,7 +54,7 @@
const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
ArrayRef<llvm::MCInst> Source = getSource();
const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
- for (const std::pair<ResourceRef, ResourceCycles> &Use :
+ for (const std::pair<ResourceRef, ReleaseAtCycles> &Use :
IssueEvent.UsedResources) {
const ResourceRef &RR = Use.first;
assert(Resource2VecIndex.contains(RR.first));
@@ -181,7 +181,7 @@
ArrayRef<llvm::MCInst> Source = getSource();
const unsigned Executions = LastInstructionIdx / Source.size() + 1;
for (const auto &R : enumerate(ResourceUsage)) {
- const ResourceCycles &RU = R.value();
+ const ReleaseAtCycles &RU = R.value();
if (RU.getNumerator() == 0)
continue;
unsigned InstructionIndex = R.index() / NumResourceUnits;
diff --git a/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.h b/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.h
index c3993a0..be8ad04 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.h
+++ b/src/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.h
@@ -78,7 +78,7 @@
llvm::DenseMap<unsigned, unsigned> Resource2VecIndex;
// Table of resources used by instructions.
- std::vector<ResourceCycles> ResourceUsage;
+ std::vector<ReleaseAtCycles> ResourceUsage;
unsigned NumResourceUnits;
void printResourcePressurePerIter(llvm::raw_ostream &OS) const;
diff --git a/src/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.h b/src/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.h
index 21f3fad..c99905d 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.h
+++ b/src/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.h
@@ -28,7 +28,6 @@
#ifndef LLVM_TOOLS_LLVM_MCA_SUMMARYVIEW_H
#define LLVM_TOOLS_LLVM_MCA_SUMMARYVIEW_H
-#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCSchedule.h"
#include "llvm/MCA/View.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt
index 2b2a116a..3009717 100644
--- a/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt
@@ -18,4 +18,7 @@
add_llvm_tool(llvm-ml
llvm-ml.cpp
Disassembler.cpp
+ DEPENDS
+ MLTableGen
+ GENERATE_DRIVER
)
diff --git a/src/llvm-project/llvm/tools/llvm-ml/llvm-ml.cpp b/src/llvm-project/llvm/tools/llvm-ml/llvm-ml.cpp
index 34691c4..1cac576 100644
--- a/src/llvm-project/llvm/tools/llvm-ml/llvm-ml.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ml/llvm-ml.cpp
@@ -34,7 +34,7 @@
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -53,9 +53,7 @@
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -68,13 +66,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -90,7 +82,7 @@
StringRef DefaultBitness = "32";
SmallString<255> Program = ProgName;
sys::path::replace_extension(Program, "");
- if (Program.endswith("ml64"))
+ if (Program.ends_with("ml64"))
DefaultBitness = "64";
StringRef TripleName =
@@ -193,8 +185,7 @@
return Res;
}
-int main(int Argc, char **Argv) {
- InitLLVM X(Argc, Argv);
+int llvm_ml_main(int Argc, char **Argv, const llvm::ToolContext &) {
StringRef ProgName = sys::path::filename(Argv[0]);
// Initialize targets and assembly printers/parsers.
diff --git a/src/llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp b/src/llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp
index 887cc90..158088d 100644
--- a/src/llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp
@@ -16,7 +16,6 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -35,9 +34,7 @@
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -49,14 +46,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
-{ \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -84,8 +76,6 @@
}
int llvm_mt_main(int Argc, char **Argv, const llvm::ToolContext &) {
- InitLLVM X(Argc, Argv);
-
CvtResOptTable T;
unsigned MAI, MAC;
ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
diff --git a/src/llvm-project/llvm/tools/llvm-nm/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-nm/CMakeLists.txt
index ec04f1e..5191e13 100644
--- a/src/llvm-project/llvm/tools/llvm-nm/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-nm/CMakeLists.txt
@@ -8,6 +8,7 @@
Object
Option
Support
+ Symbolize
TargetParser
TextAPI
)
diff --git a/src/llvm-project/llvm/tools/llvm-nm/Opts.td b/src/llvm-project/llvm/tools/llvm-nm/Opts.td
index 60ac134..04d9f5d 100644
--- a/src/llvm-project/llvm/tools/llvm-nm/Opts.td
+++ b/src/llvm-project/llvm/tools/llvm-nm/Opts.td
@@ -22,6 +22,7 @@
def extern_only : FF<"extern-only", "Show only external symbols">;
defm format : Eq<"format", "Specify output format: bsd (default), posix, sysv, darwin, just-symbols">, MetaVarName<"<format>">;
def help : FF<"help", "Display this help">;
+def line_numbers : FF<"line-numbers", "Use debugging information to print symbols' filenames and line numbers">;
def no_llvm_bc : FF<"no-llvm-bc", "Disable LLVM bitcode reader">;
def no_sort : FF<"no-sort", "Show symbols in order encountered">;
def no_weak : FF<"no-weak", "Show only non-weak symbols">;
@@ -67,6 +68,7 @@
def : F<"h", "Alias for --help">, Alias<help>;
def : F<"g", "Alias for --extern-only">, Alias<extern_only>;
def : F<"j", "Alias for --format=just-symbols">, Alias<format_EQ>, AliasArgs<["just-symbols"]>;
+def : F<"l", "Alias for --line-numbers">, Alias<line_numbers>;
def : F<"m", "Alias for --format=darwin">, Alias<format_EQ>, AliasArgs<["darwin"]>;
def : F<"M", "Deprecated alias for --print-armap">, Alias<print_armap>, Flags<[HelpHidden]>;
def : F<"n", "Alias for --numeric-sort">, Alias<numeric_sort>;
diff --git a/src/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp b/src/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp
index 1f6a5d1..da5998b 100644
--- a/src/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/src/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -17,7 +17,9 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/BinaryFormat/XCOFF.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
@@ -29,6 +31,7 @@
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
#include "llvm/Object/TapiFile.h"
#include "llvm/Object/TapiUniversal.h"
#include "llvm/Object/Wasm.h"
@@ -39,7 +42,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
@@ -58,9 +60,7 @@
using namespace llvm::opt; // for HelpHidden in Opts.inc
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -73,13 +73,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -103,6 +97,7 @@
static bool DynamicSyms;
static bool ExportSymbols;
static bool ExternalOnly;
+static bool LineNumbers;
static OutputFormatTy OutputFormat;
static bool NoLLVMBitcode;
static bool NoSort;
@@ -243,10 +238,8 @@
std::string IndirectName;
bool isDefined() const {
- if (Sym.getRawDataRefImpl().p) {
- uint32_t Flags = cantFail(Sym.getFlags());
- return !(Flags & SymbolRef::SF_Undefined);
- }
+ if (Sym.getRawDataRefImpl().p)
+ return !(SymFlags & SymbolRef::SF_Undefined);
return TypeChar != 'U';
}
@@ -559,8 +552,6 @@
}
}
}
-
- outs() << "\n";
}
// Table that maps Darwin's Mach-O stab constants to strings to allow printing.
@@ -569,37 +560,22 @@
const char *Name;
};
const struct DarwinStabName DarwinStabNames[] = {
- {MachO::N_GSYM, "GSYM"},
- {MachO::N_FNAME, "FNAME"},
- {MachO::N_FUN, "FUN"},
- {MachO::N_STSYM, "STSYM"},
- {MachO::N_LCSYM, "LCSYM"},
- {MachO::N_BNSYM, "BNSYM"},
- {MachO::N_PC, "PC"},
- {MachO::N_AST, "AST"},
- {MachO::N_OPT, "OPT"},
- {MachO::N_RSYM, "RSYM"},
- {MachO::N_SLINE, "SLINE"},
- {MachO::N_ENSYM, "ENSYM"},
- {MachO::N_SSYM, "SSYM"},
- {MachO::N_SO, "SO"},
- {MachO::N_OSO, "OSO"},
- {MachO::N_LSYM, "LSYM"},
- {MachO::N_BINCL, "BINCL"},
- {MachO::N_SOL, "SOL"},
- {MachO::N_PARAMS, "PARAM"},
- {MachO::N_VERSION, "VERS"},
- {MachO::N_OLEVEL, "OLEV"},
- {MachO::N_PSYM, "PSYM"},
- {MachO::N_EINCL, "EINCL"},
- {MachO::N_ENTRY, "ENTRY"},
- {MachO::N_LBRAC, "LBRAC"},
- {MachO::N_EXCL, "EXCL"},
- {MachO::N_RBRAC, "RBRAC"},
- {MachO::N_BCOMM, "BCOMM"},
- {MachO::N_ECOMM, "ECOMM"},
- {MachO::N_ECOML, "ECOML"},
- {MachO::N_LENG, "LENG"},
+ {MachO::N_GSYM, "GSYM"}, {MachO::N_FNAME, "FNAME"},
+ {MachO::N_FUN, "FUN"}, {MachO::N_STSYM, "STSYM"},
+ {MachO::N_LCSYM, "LCSYM"}, {MachO::N_BNSYM, "BNSYM"},
+ {MachO::N_PC, "PC"}, {MachO::N_AST, "AST"},
+ {MachO::N_OPT, "OPT"}, {MachO::N_RSYM, "RSYM"},
+ {MachO::N_SLINE, "SLINE"}, {MachO::N_ENSYM, "ENSYM"},
+ {MachO::N_SSYM, "SSYM"}, {MachO::N_SO, "SO"},
+ {MachO::N_OSO, "OSO"}, {MachO::N_LIB, "LIB"},
+ {MachO::N_LSYM, "LSYM"}, {MachO::N_BINCL, "BINCL"},
+ {MachO::N_SOL, "SOL"}, {MachO::N_PARAMS, "PARAM"},
+ {MachO::N_VERSION, "VERS"}, {MachO::N_OLEVEL, "OLEV"},
+ {MachO::N_PSYM, "PSYM"}, {MachO::N_EINCL, "EINCL"},
+ {MachO::N_ENTRY, "ENTRY"}, {MachO::N_LBRAC, "LBRAC"},
+ {MachO::N_EXCL, "EXCL"}, {MachO::N_RBRAC, "RBRAC"},
+ {MachO::N_BCOMM, "BCOMM"}, {MachO::N_ECOMM, "ECOMM"},
+ {MachO::N_ECOML, "ECOML"}, {MachO::N_LENG, "LENG"},
};
static const char *getDarwinStabString(uint8_t NType) {
@@ -637,30 +613,6 @@
outs() << format(" %02x", NType);
}
-static std::optional<std::string> demangle(StringRef Name) {
- std::string Demangled;
- if (nonMicrosoftDemangle(Name, Demangled))
- return Demangled;
- return std::nullopt;
-}
-
-static std::optional<std::string> demangleXCOFF(StringRef Name) {
- if (Name.empty() || Name[0] != '.')
- return demangle(Name);
-
- Name = Name.drop_front();
- std::optional<std::string> DemangledName = demangle(Name);
- if (DemangledName)
- return "." + *DemangledName;
- return std::nullopt;
-}
-
-static std::optional<std::string> demangleMachO(StringRef Name) {
- if (!Name.empty() && Name[0] == '_')
- Name = Name.drop_front();
- return demangle(Name);
-}
-
static bool symbolIsDefined(const NMSymbol &Sym) {
return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
}
@@ -697,9 +649,88 @@
}
}
+static void printLineNumbers(symbolize::LLVMSymbolizer &Symbolizer,
+ const NMSymbol &S) {
+ const auto *Obj = dyn_cast<ObjectFile>(S.Sym.getObject());
+ if (!Obj)
+ return;
+ const SymbolRef Sym(S.Sym);
+ uint64_t SectionIndex = object::SectionedAddress::UndefSection;
+ section_iterator Sec = cantFail(Sym.getSection());
+ if (Sec != Obj->section_end())
+ SectionIndex = Sec->getIndex();
+ object::SectionedAddress Address = {cantFail(Sym.getAddress()), SectionIndex};
+
+ std::string FileName;
+ uint32_t Line;
+ switch (S.TypeChar) {
+ // For undefined symbols, find the first relocation for that symbol with a
+ // line number.
+ case 'U': {
+ for (const SectionRef RelocsSec : Obj->sections()) {
+ if (RelocsSec.relocations().empty())
+ continue;
+ SectionRef TextSec = *cantFail(RelocsSec.getRelocatedSection());
+ if (!TextSec.isText())
+ continue;
+ for (const RelocationRef R : RelocsSec.relocations()) {
+ if (R.getSymbol() != Sym)
+ continue;
+ Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(
+ *Obj, {TextSec.getAddress() + R.getOffset(), SectionIndex});
+ if (!ResOrErr) {
+ error(ResOrErr.takeError(), Obj->getFileName());
+ return;
+ }
+ if (ResOrErr->FileName == DILineInfo::BadString)
+ return;
+ FileName = std::move(ResOrErr->FileName);
+ Line = ResOrErr->Line;
+ break;
+ }
+ if (!FileName.empty())
+ break;
+ }
+ if (FileName.empty())
+ return;
+ break;
+ }
+ case 't':
+ case 'T': {
+ Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(*Obj, Address);
+ if (!ResOrErr) {
+ error(ResOrErr.takeError(), Obj->getFileName());
+ return;
+ }
+ if (ResOrErr->FileName == DILineInfo::BadString)
+ return;
+ FileName = std::move(ResOrErr->FileName);
+ Line = ResOrErr->Line;
+ break;
+ }
+ default: {
+ Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(*Obj, Address);
+ if (!ResOrErr) {
+ error(ResOrErr.takeError(), Obj->getFileName());
+ return;
+ }
+ if (ResOrErr->DeclFile.empty())
+ return;
+ FileName = std::move(ResOrErr->DeclFile);
+ Line = ResOrErr->DeclLine;
+ break;
+ }
+ }
+ outs() << '\t' << FileName << ':' << Line;
+}
+
static void printSymbolList(SymbolicFile &Obj,
std::vector<NMSymbol> &SymbolList, bool printName,
StringRef ArchiveName, StringRef ArchitectureName) {
+ std::optional<symbolize::LLVMSymbolizer> Symbolizer;
+ if (LineNumbers)
+ Symbolizer.emplace();
+
if (!PrintFileName) {
if ((OutputFormat == bsd || OutputFormat == posix ||
OutputFormat == just_symbols) &&
@@ -751,15 +782,8 @@
std::string Name = S.Name;
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
- if (Demangle) {
- function_ref<std::optional<std::string>(StringRef)> Fn = ::demangle;
- if (Obj.isXCOFF())
- Fn = demangleXCOFF;
- if (Obj.isMachO())
- Fn = demangleMachO;
- if (std::optional<std::string> Opt = Fn(S.Name))
- Name = *Opt;
- }
+ if (Demangle)
+ Name = demangle(Name);
if (PrintFileName)
writeFileName(outs(), ArchiveName, ArchitectureName);
@@ -806,7 +830,7 @@
printFormat);
} else if (OutputFormat == posix) {
outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
- << (MachO ? "0" : SymbolSizeStr) << "\n";
+ << (MachO ? "0" : SymbolSizeStr);
} else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
if (PrintAddress)
outs() << SymbolAddrStr << ' ';
@@ -827,12 +851,14 @@
} else
outs() << S.IndirectName << ")";
}
- outs() << "\n";
} else if (OutputFormat == sysv) {
outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| "
<< S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|"
- << SymbolSizeStr << "| |" << S.SectionName << "\n";
+ << SymbolSizeStr << "| |" << S.SectionName;
}
+ if (LineNumbers)
+ printLineNumbers(*Symbolizer, S);
+ outs() << '\n';
}
SymbolList.clear();
@@ -873,7 +899,7 @@
consumeError(NameOrErr.takeError());
return '?';
}
- if ((*NameOrErr).startswith(".debug"))
+ if ((*NameOrErr).starts_with(".debug"))
return 'N';
if (!(Flags & ELF::SHF_WRITE))
return 'n';
@@ -912,7 +938,7 @@
const coff_section *Section = Obj.getCOFFSection(*SecI);
Characteristics = Section->Characteristics;
if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
- if (NameOrErr->startswith(".idata"))
+ if (NameOrErr->starts_with(".idata"))
return 'i';
}
@@ -1031,10 +1057,12 @@
static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) {
auto Type = cantFail(Obj.getSymbolType(I->getRawDataRefImpl()));
switch (Type) {
- case SymbolRef::ST_Data:
- return 'd';
case SymbolRef::ST_Function:
return 't';
+ case SymbolRef::ST_Data:
+ if (Obj.hasSegmentInfo())
+ return 'd';
+ [[fallthrough]];
default:
return 's';
}
@@ -1709,13 +1737,13 @@
StringRef SymName = cantFail(Sym.getName());
if (SymName.empty())
continue;
- if (SymName.startswith("__sinit") || SymName.startswith("__sterm") ||
+ if (SymName.starts_with("__sinit") || SymName.starts_with("__sterm") ||
SymName.front() == '.' || SymName.front() == '(')
continue;
// Check the SymName regex matching with "^__[0-9]+__".
- if (SymName.size() > 4 && SymName.startswith("__") &&
- SymName.endswith("__")) {
+ if (SymName.size() > 4 && SymName.starts_with("__") &&
+ SymName.ends_with("__")) {
if (std::all_of(SymName.begin() + 2, SymName.end() - 2, isDigit))
continue;
}
@@ -1723,9 +1751,9 @@
if (SymName == "__rsrc" && NoRsrc)
continue;
- if (SymName.startswith("__tf1"))
+ if (SymName.starts_with("__tf1"))
SymName = SymName.substr(6);
- else if (SymName.startswith("__tf9"))
+ else if (SymName.starts_with("__tf9"))
SymName = SymName.substr(14);
NMSymbol S = {};
@@ -1802,9 +1830,12 @@
// are used to repesent mapping symbols and needed to honor the
// --special-syms option.
auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj);
- if ((!ELFObj || (ELFObj->getEMachine() != ELF::EM_ARM &&
- ELFObj->getEMachine() != ELF::EM_AARCH64)) &&
- !DebugSyms && (*SymFlagsOrErr & SymbolRef::SF_FormatSpecific))
+ bool HasMappingSymbol =
+ ELFObj && llvm::is_contained({ELF::EM_ARM, ELF::EM_AARCH64,
+ ELF::EM_CSKY, ELF::EM_RISCV},
+ ELFObj->getEMachine());
+ if (!HasMappingSymbol && !DebugSyms &&
+ (*SymFlagsOrErr & SymbolRef::SF_FormatSpecific))
continue;
if (WithoutAliases && (*SymFlagsOrErr & SymbolRef::SF_Indirect))
continue;
@@ -1823,6 +1854,12 @@
dyn_cast<const XCOFFObjectFile>(&Obj))
S.Size = XCOFFObj->getSymbolSize(Sym.getRawDataRefImpl());
+ if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj)) {
+ const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym);
+ if (WasmSym.isTypeData() && !WasmSym.isUndefined())
+ S.Size = WasmSym.Info.DataRef.Size;
+ }
+
if (PrintAddress && isa<ObjectFile>(Obj)) {
SymbolRef SymRef(Sym);
Expected<uint64_t> AddressOrErr = SymRef.getAddress();
@@ -1889,6 +1926,62 @@
return !Obj.symbols().empty();
}
+static void printSymbolNamesFromObject(
+ SymbolicFile &Obj, std::vector<NMSymbol> &SymbolList,
+ bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {},
+ StringRef ArchitectureName = {}, StringRef ObjectName = {},
+ bool PrintArchiveName = true) {
+
+ if (PrintObjectLabel && !ExportSymbols)
+ printObjectLabel(PrintArchiveName, ArchiveName, ArchitectureName,
+ ObjectName.empty() ? Obj.getFileName() : ObjectName);
+
+ if (!getSymbolNamesFromObject(Obj, SymbolList) || ExportSymbols)
+ return;
+
+ // If there is an error in hasSymbols(), the error should be encountered in
+ // function getSymbolNamesFromObject first.
+ if (!cantFail(hasSymbols(Obj)) && SymbolList.empty() && !Quiet) {
+ writeFileName(errs(), ArchiveName, ArchitectureName);
+ errs() << "no symbols\n";
+ }
+
+ sortSymbolList(SymbolList);
+ printSymbolList(Obj, SymbolList, PrintSymbolObject, ArchiveName,
+ ArchitectureName);
+}
+
+static void dumpSymbolsNameFromMachOFilesetEntry(
+ MachOObjectFile *Obj, std::vector<NMSymbol> &SymbolList,
+ bool PrintSymbolObject, bool PrintObjectLabel) {
+ auto Buf = Obj->getMemoryBufferRef();
+ const auto *End = Obj->load_commands().end();
+ for (const auto *It = Obj->load_commands().begin(); It != End; ++It) {
+ const auto &Command = *It;
+ if (Command.C.cmd != MachO::LC_FILESET_ENTRY)
+ continue;
+
+ MachO::fileset_entry_command Entry =
+ Obj->getFilesetEntryLoadCommand(Command);
+ auto MaybeMachO =
+ MachOObjectFile::createMachOObjectFile(Buf, 0, 0, Entry.fileoff);
+
+ if (Error Err = MaybeMachO.takeError())
+ report_fatal_error(std::move(Err));
+
+ const char *EntryName = Command.Ptr + Entry.entry_id.offset;
+ if (EntryName)
+ outs() << "Symbols for " << EntryName << ": \n";
+
+ std::unique_ptr<MachOObjectFile> EntryMachO = std::move(MaybeMachO.get());
+ printSymbolNamesFromObject(*EntryMachO, SymbolList, PrintSymbolObject,
+ PrintObjectLabel);
+
+ if (std::next(It) != End)
+ outs() << "\n";
+ }
+}
+
static void dumpSymbolNamesFromObject(
SymbolicFile &Obj, std::vector<NMSymbol> &SymbolList,
bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {},
@@ -1903,23 +1996,21 @@
return;
}
- if (PrintObjectLabel && !ExportSymbols)
- printObjectLabel(PrintArchiveName, ArchiveName, ArchitectureName,
- ObjectName.empty() ? Obj.getFileName() : ObjectName);
- if (!getSymbolNamesFromObject(Obj, SymbolList) || ExportSymbols)
- return;
CurrentFilename = Obj.getFileName();
- // If there is an error in hasSymbols(), the error should be encountered in
- // function getSymbolNamesFromObject first.
- if (!cantFail(hasSymbols(Obj)) && SymbolList.empty() && !Quiet) {
- writeFileName(errs(), ArchiveName, ArchitectureName);
- errs() << "no symbols\n";
+ // Are we handling a MachO of type MH_FILESET?
+ if (Obj.isMachO() && Obj.is64Bit() &&
+ cast<MachOObjectFile>(&Obj)->getHeader64().filetype ==
+ MachO::MH_FILESET) {
+ dumpSymbolsNameFromMachOFilesetEntry(cast<MachOObjectFile>(&Obj),
+ SymbolList, PrintSymbolObject,
+ PrintObjectLabel);
+ return;
}
- sortSymbolList(SymbolList);
- printSymbolList(Obj, SymbolList, PrintSymbolObject, ArchiveName,
- ArchitectureName);
+ printSymbolNamesFromObject(Obj, SymbolList, PrintSymbolObject,
+ PrintObjectLabel, ArchiveName, ArchitectureName,
+ ObjectName, PrintArchiveName);
}
// checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
@@ -2267,6 +2358,14 @@
if (error(BufferOrErr.getError(), Filename))
return SymbolList;
+ // Ignore AIX linker import files (these files start with "#!"), when
+ // exporting symbols.
+ const char *BuffStart = (*BufferOrErr)->getBufferStart();
+ size_t BufferSize = (*BufferOrErr)->getBufferSize();
+ if (ExportSymbols && BufferSize >= 2 && BuffStart[0] == '#' &&
+ BuffStart[1] == '!')
+ return SymbolList;
+
LLVMContext Context;
LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
Expected<std::unique_ptr<Binary>> BinaryOrErr =
@@ -2305,7 +2404,6 @@
}
int llvm_nm_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
NmOptTable Tbl;
@@ -2350,6 +2448,7 @@
else
error("--format value should be one of: bsd, posix, sysv, darwin, "
"just-symbols");
+ LineNumbers = Args.hasArg(OPT_line_numbers);
NoLLVMBitcode = Args.hasArg(OPT_no_llvm_bc);
NoSort = Args.hasArg(OPT_no_sort);
NoWeakSymbols = Args.hasArg(OPT_no_weak);
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 265e4fc..f63e5c6 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -10,7 +10,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/ObjCopy/CommonConfig.h"
#include "llvm/ObjCopy/ConfigManager.h"
@@ -26,13 +25,12 @@
using namespace llvm;
using namespace llvm::objcopy;
+using namespace llvm::opt;
namespace {
enum ObjcopyID {
OBJCOPY_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OBJCOPY_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),
#include "ObjcopyOpts.inc"
#undef OPTION
};
@@ -46,12 +44,8 @@
#undef PREFIX
static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, \
- METAVAR, OBJCOPY_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OBJCOPY_##GROUP, \
- OBJCOPY_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) \
+ LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),
#include "ObjcopyOpts.inc"
#undef OPTION
};
@@ -66,9 +60,8 @@
enum InstallNameToolID {
INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- INSTALL_NAME_TOOL_##ID,
+#define OPTION(...) \
+ LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),
#include "InstallNameToolOpts.inc"
#undef OPTION
};
@@ -83,20 +76,8 @@
#undef PREFIX
static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- INSTALL_NAME_TOOL_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- INSTALL_NAME_TOOL_##GROUP, \
- INSTALL_NAME_TOOL_##ALIAS, \
- ALIASARGS, \
- VALUES},
+#define OPTION(...) \
+ LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),
#include "InstallNameToolOpts.inc"
#undef OPTION
};
@@ -110,9 +91,8 @@
enum BitcodeStripID {
BITCODE_STRIP_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- BITCODE_STRIP_##ID,
+#define OPTION(...) \
+ LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),
#include "BitcodeStripOpts.inc"
#undef OPTION
};
@@ -127,20 +107,8 @@
#undef PREFIX
static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- BITCODE_STRIP_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- BITCODE_STRIP_##GROUP, \
- BITCODE_STRIP_##ALIAS, \
- ALIASARGS, \
- VALUES},
+#define OPTION(...) \
+ LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),
#include "BitcodeStripOpts.inc"
#undef OPTION
};
@@ -154,9 +122,7 @@
enum StripID {
STRIP_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- STRIP_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),
#include "StripOpts.inc"
#undef OPTION
};
@@ -170,12 +136,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info StripInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, \
- METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, STRIP_##GROUP, \
- STRIP_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),
#include "StripOpts.inc"
#undef OPTION
};
@@ -205,6 +166,7 @@
.CaseLower("contents", SectionFlag::SecContents)
.CaseLower("share", SectionFlag::SecShare)
.CaseLower("exclude", SectionFlag::SecExclude)
+ .CaseLower("large", SectionFlag::SecLarge)
.Default(SectionFlag::SecNone);
}
@@ -218,7 +180,7 @@
errc::invalid_argument,
"unrecognized section flag '%s'. Flags supported for GNU "
"compatibility: alloc, load, noload, readonly, exclude, debug, "
- "code, data, rom, share, contents, merge, strings",
+ "code, data, rom, share, contents, merge, strings, large",
Flag.str().c_str());
ParsedFlags |= ParsedFlag;
}
@@ -337,6 +299,8 @@
// LoongArch
{"elf32-loongarch", {ELF::EM_LOONGARCH, false, true}},
{"elf64-loongarch", {ELF::EM_LOONGARCH, true, true}},
+ // SystemZ
+ {"elf64-s390", {ELF::EM_S390, true, false}},
};
static Expected<TargetInfo>
@@ -353,7 +317,7 @@
MI.OSABI = ELF::ELFOSABI_FREEBSD;
FileFormat Format;
- if (TargetName.startswith("elf"))
+ if (TargetName.starts_with("elf"))
Format = FileFormat::ELF;
else
// This should never happen because `TargetName` is valid (it certainly
@@ -775,6 +739,35 @@
if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
Config.ExtractPartition = Arg->getValue();
+ if (const auto *A = InputArgs.getLastArg(OBJCOPY_gap_fill)) {
+ if (Config.OutputFormat != FileFormat::Binary)
+ return createStringError(
+ errc::invalid_argument,
+ "'--gap-fill' is only supported for binary output");
+ ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(A->getValue());
+ if (!Val)
+ return createStringError(Val.getError(), "--gap-fill: bad number: %s",
+ A->getValue());
+ uint8_t ByteVal = Val.get();
+ if (ByteVal != Val.get())
+ return createStringError(std::errc::value_too_large,
+ "gap-fill value %s is out of range (0 to 0xff)",
+ A->getValue());
+ Config.GapFill = ByteVal;
+ }
+
+ if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) {
+ if (Config.OutputFormat != FileFormat::Binary)
+ return createStringError(
+ errc::invalid_argument,
+ "'--pad-to' is only supported for binary output");
+ ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue());
+ if (!Addr)
+ return createStringError(Addr.getError(), "--pad-to: bad number: %s",
+ A->getValue());
+ Config.PadTo = *Addr;
+ }
+
for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
if (!StringRef(Arg->getValue()).contains('='))
return createStringError(errc::invalid_argument,
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.h b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.h
index f7fa2af..3b88789 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.h
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.h
@@ -11,7 +11,6 @@
#include "llvm/ObjCopy/ConfigManager.h"
#include "llvm/Support/Allocator.h"
-#include <vector>
namespace llvm {
namespace objcopy {
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index a7e4263..ead8cd2 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -52,7 +52,7 @@
"Renames a section from old to new, optionally with specified flags. "
"Flags supported for GNU compatibility: alloc, load, noload, "
"readonly, exclude, debug, code, data, rom, share, contents, merge, "
- "strings">,
+ "strings, large">,
MetaVarName<"old=new[,flag1,...]">;
defm redefine_symbol
: Eq<"redefine-sym", "Change the name of a symbol old to new">,
@@ -85,7 +85,7 @@
: Eq<"set-section-flags",
"Set section flags for a given section. Flags supported for GNU "
"compatibility: alloc, load, noload, readonly, exclude, debug, code, "
- "data, rom, share, contents, merge, strings">,
+ "data, rom, share, contents, merge, strings, large">,
MetaVarName<"section=flag1[,flag2,...]">;
defm set_section_type
@@ -230,3 +230,15 @@
defm update_section
: Eq<"update-section", "Replace the contents of section <name> with contents from a file <file>">,
MetaVarName<"name=file">;
+
+defm gap_fill
+ : Eq<"gap-fill", "Fill the gaps between sections with <value> instead of zero. "
+ "<value> must be an unsigned 8-bit integer. "
+ "This option is only supported for ELF input and binary output">,
+ MetaVarName<"value">;
+
+defm pad_to
+ : Eq<"pad-to", "Pad the output up to the load address <address>, using a value "
+ "of zero or the value specified by the --gap-fill option. "
+ "This option is only supported for ELF input and binary output">,
+ MetaVarName<"address">;
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/src/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index 2afa976..730f423 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -42,7 +42,6 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
@@ -56,7 +55,6 @@
#include <cassert>
#include <cstdlib>
#include <memory>
-#include <string>
#include <system_error>
#include <utility>
@@ -225,7 +223,6 @@
}
int llvm_objcopy_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
ToolName = argv[0];
// Expand response files.
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt
index 65d2f92..0306736 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt
@@ -3,6 +3,7 @@
AllTargetsDisassemblers
AllTargetsInfos
BinaryFormat
+ DebugInfoBTF
DebugInfoDWARF
Demangle
MC
@@ -34,12 +35,11 @@
DEPENDS
ObjdumpOptsTableGen
OtoolOptsTableGen
+ GENERATE_DRIVER
)
-target_link_libraries(llvm-objdump PRIVATE LLVMDebuginfod)
-
-if(LLVM_HAVE_LIBXAR)
- target_link_libraries(llvm-objdump PRIVATE ${XAR_LIB})
+if(NOT LLVM_TOOL_LLVM_DRIVER_BUILD)
+ target_link_libraries(llvm-objdump PRIVATE LLVMDebuginfod)
endif()
add_llvm_tool_symlink(llvm-otool llvm-objdump)
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
index e1b3847..71697fa 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -45,7 +45,7 @@
}
template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;
- void printPrivateHeaders(bool MachOOnlyFirst) override;
+ void printPrivateHeaders() override;
private:
template <typename T> FormattedNumber formatAddr(T V) const {
@@ -771,7 +771,7 @@
}
}
-void COFFDumper::printPrivateHeaders(bool MachOOnlyFirst) {
+void COFFDumper::printPrivateHeaders() {
COFFDumper CD(Obj);
const uint16_t Cha = Obj.getCharacteristics();
outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n';
@@ -857,7 +857,7 @@
<< "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
<< "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
<< Name;
- if (Demangle && Name.startswith("?")) {
+ if (Demangle && Name.starts_with("?")) {
int Status = -1;
char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
index 5b08a4b..fda99bd 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -28,7 +28,7 @@
template <typename ELFT> class ELFDumper : public Dumper {
public:
ELFDumper(const ELFObjectFile<ELFT> &O) : Dumper(O), Obj(O) {}
- void printPrivateHeaders(bool MachOOnlyFirst) override;
+ void printPrivateHeaders() override;
void printDynamicRelocations() override;
private:
@@ -38,6 +38,7 @@
void printDynamicSection();
void printProgramHeaders();
void printSymbolVersion();
+ void printSymbolVersionDependency(const typename ELFT::Shdr &Sec);
};
} // namespace
@@ -180,8 +181,10 @@
// Search for a PT_LOAD segment containing the requested section. Use this
// segment's p_addr to calculate the section's LMA.
for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
- if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
- (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
+ if ((Phdr.p_type == ELF::PT_LOAD) &&
+ (isSectionInSegment<ELFT>(
+ Phdr, *cast<const ELFObjectFile<ELFT>>(Sec.getObject())
+ ->getSection(Sec.getRawDataRefImpl()))))
return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;
// Return section's VMA if it isn't in a PT_LOAD segment.
@@ -282,9 +285,15 @@
case ELF::PT_OPENBSD_MUTABLE:
outs() << "OPENBSD_MUTABLE ";
break;
+ case ELF::PT_OPENBSD_NOBTCFI:
+ outs() << "OPENBSD_NOBTCFI ";
+ break;
case ELF::PT_OPENBSD_RANDOMIZE:
outs() << "OPENBSD_RANDOMIZE ";
break;
+ case ELF::PT_OPENBSD_SYSCALLS:
+ outs() << "OPENBSD_SYSCALLS ";
+ break;
case ELF::PT_OPENBSD_WXNEEDED:
outs() << "OPENBSD_WXNEEDED ";
break;
@@ -346,19 +355,13 @@
}
template <class ELFT>
-static void printSymbolVersionDependency(StringRef FileName,
- const ELFFile<ELFT> &Obj,
- const typename ELFT::Shdr &Sec) {
+void ELFDumper<ELFT>::printSymbolVersionDependency(
+ const typename ELFT::Shdr &Sec) {
outs() << "\nVersion References:\n";
-
- auto WarningHandler = [&](const Twine &Msg) {
- reportWarning(Msg, FileName);
- return Error::success();
- };
Expected<std::vector<VerNeed>> V =
- Obj.getVersionDependencies(Sec, WarningHandler);
+ getELFFile().getVersionDependencies(Sec, this->WarningHandler);
if (!V) {
- reportWarning(toString(V.takeError()), FileName);
+ reportWarning(toString(V.takeError()), Obj.getFileName());
return;
}
@@ -420,13 +423,13 @@
StringRef StrTab = unwrapOrError(Elf.getStringTable(*StrTabSec), FileName);
if (Shdr.sh_type == ELF::SHT_GNU_verneed)
- printSymbolVersionDependency<ELFT>(FileName, Elf, Shdr);
+ printSymbolVersionDependency(Shdr);
else
printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
}
}
-template <class ELFT> void ELFDumper<ELFT>::printPrivateHeaders(bool) {
+template <class ELFT> void ELFDumper<ELFT>::printPrivateHeaders() {
printProgramHeaders();
printDynamicSection();
printSymbolVersion();
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
index 11fb1cb..0e6935c 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
@@ -53,12 +53,6 @@
#include <cstring>
#include <system_error>
-#ifdef LLVM_HAVE_LIBXAR
-extern "C" {
-#include <xar/xar.h>
-}
-#endif
-
using namespace llvm;
using namespace llvm::object;
using namespace llvm::objdump;
@@ -197,7 +191,7 @@
public:
MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}
- void printPrivateHeaders(bool OnlyFirst) override;
+ void printPrivateHeaders() override;
};
} // namespace
@@ -212,39 +206,6 @@
typedef std::vector<DiceTableEntry> DiceTable;
typedef DiceTable::iterator dice_table_iterator;
-#ifdef LLVM_HAVE_LIBXAR
-namespace {
-struct ScopedXarFile {
- xar_t xar;
- ScopedXarFile(const char *filename, int32_t flags) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- xar = xar_open(filename, flags);
-#pragma clang diagnostic pop
- }
- ~ScopedXarFile() {
- if (xar)
- xar_close(xar);
- }
- ScopedXarFile(const ScopedXarFile &) = delete;
- ScopedXarFile &operator=(const ScopedXarFile &) = delete;
- operator xar_t() { return xar; }
-};
-
-struct ScopedXarIter {
- xar_iter_t iter;
- ScopedXarIter() : iter(xar_iter_new()) {}
- ~ScopedXarIter() {
- if (iter)
- xar_iter_free(iter);
- }
- ScopedXarIter(const ScopedXarIter &) = delete;
- ScopedXarIter &operator=(const ScopedXarIter &) = delete;
- operator xar_iter_t() { return iter; }
-};
-} // namespace
-#endif // defined(LLVM_HAVE_LIBXAR)
-
// This is used to search for a data in code table entry for the PC being
// disassembled. The j parameter has the PC in j.first. A single data in code
// table entry can cover many bytes for each of its Kind's. So if the offset,
@@ -329,7 +290,7 @@
const StringRef FileName = MachOObj->getFileName();
for (const SymbolRef &Symbol : MachOObj->symbols()) {
StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
- if (!SymName.startswith("ltmp"))
+ if (!SymName.starts_with("ltmp"))
Symbols.push_back(Symbol);
}
@@ -1521,7 +1482,7 @@
ST == SymbolRef::ST_Other) {
uint64_t Address = cantFail(Symbol.getValue());
StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
- if (!SymName.startswith(".objc"))
+ if (!SymName.starts_with(".objc"))
(*AddrMap)[Address] = SymName;
}
}
@@ -1961,13 +1922,6 @@
StringRef DisSegName, StringRef DisSectName);
static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
uint32_t size, uint32_t addr);
-#ifdef LLVM_HAVE_LIBXAR
-static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
- uint32_t size, bool verbose,
- bool PrintXarHeader, bool PrintXarFileHeaders,
- std::string XarMemberName);
-#endif // defined(LLVM_HAVE_LIBXAR)
-
static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
bool verbose) {
SymbolAddressMap AddrMap;
@@ -2037,13 +1991,6 @@
DumpProtocolSection(O, sect, sect_size, sect_addr);
continue;
}
-#ifdef LLVM_HAVE_LIBXAR
- if (SegName == "__LLVM" && SectName == "__bundle") {
- DumpBitcodeSection(O, sect, sect_size, verbose, SymbolicOperands,
- ArchiveHeaders, "");
- continue;
- }
-#endif // defined(LLVM_HAVE_LIBXAR)
switch (section_type) {
case MachO::S_REGULAR:
DumpRawSectionContents(O, sect, sect_size, sect_addr);
@@ -6732,371 +6679,6 @@
}
}
-#ifdef LLVM_HAVE_LIBXAR
-static inline void swapStruct(struct xar_header &xar) {
- sys::swapByteOrder(xar.magic);
- sys::swapByteOrder(xar.size);
- sys::swapByteOrder(xar.version);
- sys::swapByteOrder(xar.toc_length_compressed);
- sys::swapByteOrder(xar.toc_length_uncompressed);
- sys::swapByteOrder(xar.cksum_alg);
-}
-
-static void PrintModeVerbose(uint32_t mode) {
- switch(mode & S_IFMT){
- case S_IFDIR:
- outs() << "d";
- break;
- case S_IFCHR:
- outs() << "c";
- break;
- case S_IFBLK:
- outs() << "b";
- break;
- case S_IFREG:
- outs() << "-";
- break;
- case S_IFLNK:
- outs() << "l";
- break;
- case S_IFSOCK:
- outs() << "s";
- break;
- default:
- outs() << "?";
- break;
- }
-
- /* owner permissions */
- if(mode & S_IREAD)
- outs() << "r";
- else
- outs() << "-";
- if(mode & S_IWRITE)
- outs() << "w";
- else
- outs() << "-";
- if(mode & S_ISUID)
- outs() << "s";
- else if(mode & S_IEXEC)
- outs() << "x";
- else
- outs() << "-";
-
- /* group permissions */
- if(mode & (S_IREAD >> 3))
- outs() << "r";
- else
- outs() << "-";
- if(mode & (S_IWRITE >> 3))
- outs() << "w";
- else
- outs() << "-";
- if(mode & S_ISGID)
- outs() << "s";
- else if(mode & (S_IEXEC >> 3))
- outs() << "x";
- else
- outs() << "-";
-
- /* other permissions */
- if(mode & (S_IREAD >> 6))
- outs() << "r";
- else
- outs() << "-";
- if(mode & (S_IWRITE >> 6))
- outs() << "w";
- else
- outs() << "-";
- if(mode & S_ISVTX)
- outs() << "t";
- else if(mode & (S_IEXEC >> 6))
- outs() << "x";
- else
- outs() << "-";
-}
-
-static void PrintXarFilesSummary(const char *XarFilename, xar_t xar) {
- xar_file_t xf;
- const char *key, *type, *mode, *user, *group, *size, *mtime, *name, *m;
- char *endp;
- uint32_t mode_value;
-
- ScopedXarIter xi;
- if (!xi) {
- WithColor::error(errs(), "llvm-objdump")
- << "can't obtain an xar iterator for xar archive " << XarFilename
- << "\n";
- return;
- }
-
- // Go through the xar's files.
- for (xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)) {
- ScopedXarIter xp;
- if(!xp){
- WithColor::error(errs(), "llvm-objdump")
- << "can't obtain an xar iterator for xar archive " << XarFilename
- << "\n";
- return;
- }
- type = nullptr;
- mode = nullptr;
- user = nullptr;
- group = nullptr;
- size = nullptr;
- mtime = nullptr;
- name = nullptr;
- for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){
- const char *val = nullptr;
- xar_prop_get(xf, key, &val);
-#if 0 // Useful for debugging.
- outs() << "key: " << key << " value: " << val << "\n";
-#endif
- if(strcmp(key, "type") == 0)
- type = val;
- if(strcmp(key, "mode") == 0)
- mode = val;
- if(strcmp(key, "user") == 0)
- user = val;
- if(strcmp(key, "group") == 0)
- group = val;
- if(strcmp(key, "data/size") == 0)
- size = val;
- if(strcmp(key, "mtime") == 0)
- mtime = val;
- if(strcmp(key, "name") == 0)
- name = val;
- }
- if(mode != nullptr){
- mode_value = strtoul(mode, &endp, 8);
- if(*endp != '\0')
- outs() << "(mode: \"" << mode << "\" contains non-octal chars) ";
- if(strcmp(type, "file") == 0)
- mode_value |= S_IFREG;
- PrintModeVerbose(mode_value);
- outs() << " ";
- }
- if(user != nullptr)
- outs() << format("%10s/", user);
- if(group != nullptr)
- outs() << format("%-10s ", group);
- if(size != nullptr)
- outs() << format("%7s ", size);
- if(mtime != nullptr){
- for(m = mtime; *m != 'T' && *m != '\0'; m++)
- outs() << *m;
- if(*m == 'T')
- m++;
- outs() << " ";
- for( ; *m != 'Z' && *m != '\0'; m++)
- outs() << *m;
- outs() << " ";
- }
- if(name != nullptr)
- outs() << name;
- outs() << "\n";
- }
-}
-
-static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
- uint32_t size, bool verbose,
- bool PrintXarHeader, bool PrintXarFileHeaders,
- std::string XarMemberName) {
- if(size < sizeof(struct xar_header)) {
- outs() << "size of (__LLVM,__bundle) section too small (smaller than size "
- "of struct xar_header)\n";
- return;
- }
- struct xar_header XarHeader;
- memcpy(&XarHeader, sect, sizeof(struct xar_header));
- if (sys::IsLittleEndianHost)
- swapStruct(XarHeader);
- if (PrintXarHeader) {
- if (!XarMemberName.empty())
- outs() << "In xar member " << XarMemberName << ": ";
- else
- outs() << "For (__LLVM,__bundle) section: ";
- outs() << "xar header\n";
- if (XarHeader.magic == XAR_HEADER_MAGIC)
- outs() << " magic XAR_HEADER_MAGIC\n";
- else
- outs() << " magic "
- << format_hex(XarHeader.magic, 10, true)
- << " (not XAR_HEADER_MAGIC)\n";
- outs() << " size " << XarHeader.size << "\n";
- outs() << " version " << XarHeader.version << "\n";
- outs() << " toc_length_compressed " << XarHeader.toc_length_compressed
- << "\n";
- outs() << "toc_length_uncompressed " << XarHeader.toc_length_uncompressed
- << "\n";
- outs() << " cksum_alg ";
- switch (XarHeader.cksum_alg) {
- case XAR_CKSUM_NONE:
- outs() << "XAR_CKSUM_NONE\n";
- break;
- case XAR_CKSUM_SHA1:
- outs() << "XAR_CKSUM_SHA1\n";
- break;
- case XAR_CKSUM_MD5:
- outs() << "XAR_CKSUM_MD5\n";
- break;
-#ifdef XAR_CKSUM_SHA256
- case XAR_CKSUM_SHA256:
- outs() << "XAR_CKSUM_SHA256\n";
- break;
-#endif
-#ifdef XAR_CKSUM_SHA512
- case XAR_CKSUM_SHA512:
- outs() << "XAR_CKSUM_SHA512\n";
- break;
-#endif
- default:
- outs() << XarHeader.cksum_alg << "\n";
- }
- }
-
- SmallString<128> XarFilename;
- int FD;
- std::error_code XarEC =
- sys::fs::createTemporaryFile("llvm-objdump", "xar", FD, XarFilename);
- if (XarEC) {
- WithColor::error(errs(), "llvm-objdump") << XarEC.message() << "\n";
- return;
- }
- ToolOutputFile XarFile(XarFilename, FD);
- raw_fd_ostream &XarOut = XarFile.os();
- StringRef XarContents(sect, size);
- XarOut << XarContents;
- XarOut.close();
- if (XarOut.has_error())
- return;
-
- ScopedXarFile xar(XarFilename.c_str(), READ);
- if (!xar) {
- WithColor::error(errs(), "llvm-objdump")
- << "can't create temporary xar archive " << XarFilename << "\n";
- return;
- }
-
- SmallString<128> TocFilename;
- std::error_code TocEC =
- sys::fs::createTemporaryFile("llvm-objdump", "toc", TocFilename);
- if (TocEC) {
- WithColor::error(errs(), "llvm-objdump") << TocEC.message() << "\n";
- return;
- }
- xar_serialize(xar, TocFilename.c_str());
-
- if (PrintXarFileHeaders) {
- if (!XarMemberName.empty())
- outs() << "In xar member " << XarMemberName << ": ";
- else
- outs() << "For (__LLVM,__bundle) section: ";
- outs() << "xar archive files:\n";
- PrintXarFilesSummary(XarFilename.c_str(), xar);
- }
-
- ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
- MemoryBuffer::getFileOrSTDIN(TocFilename.c_str());
- if (std::error_code EC = FileOrErr.getError()) {
- WithColor::error(errs(), "llvm-objdump") << EC.message() << "\n";
- return;
- }
- std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
-
- if (!XarMemberName.empty())
- outs() << "In xar member " << XarMemberName << ": ";
- else
- outs() << "For (__LLVM,__bundle) section: ";
- outs() << "xar table of contents:\n";
- outs() << Buffer->getBuffer() << "\n";
-
- // TODO: Go through the xar's files.
- ScopedXarIter xi;
- if(!xi){
- WithColor::error(errs(), "llvm-objdump")
- << "can't obtain an xar iterator for xar archive "
- << XarFilename.c_str() << "\n";
- return;
- }
- for(xar_file_t xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)){
- const char *key;
- const char *member_name, *member_type, *member_size_string;
- size_t member_size;
-
- ScopedXarIter xp;
- if(!xp){
- WithColor::error(errs(), "llvm-objdump")
- << "can't obtain an xar iterator for xar archive "
- << XarFilename.c_str() << "\n";
- return;
- }
- member_name = NULL;
- member_type = NULL;
- member_size_string = NULL;
- for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){
- const char *val = nullptr;
- xar_prop_get(xf, key, &val);
-#if 0 // Useful for debugging.
- outs() << "key: " << key << " value: " << val << "\n";
-#endif
- if (strcmp(key, "name") == 0)
- member_name = val;
- if (strcmp(key, "type") == 0)
- member_type = val;
- if (strcmp(key, "data/size") == 0)
- member_size_string = val;
- }
- /*
- * If we find a file with a name, date/size and type properties
- * and with the type being "file" see if that is a xar file.
- */
- if (member_name != NULL && member_type != NULL &&
- strcmp(member_type, "file") == 0 &&
- member_size_string != NULL){
- // Extract the file into a buffer.
- char *endptr;
- member_size = strtoul(member_size_string, &endptr, 10);
- if (*endptr == '\0' && member_size != 0) {
- char *buffer;
- if (xar_extract_tobuffersz(xar, xf, &buffer, &member_size) == 0) {
-#if 0 // Useful for debugging.
- outs() << "xar member: " << member_name << " extracted\n";
-#endif
- // Set the XarMemberName we want to see printed in the header.
- std::string OldXarMemberName;
- // If XarMemberName is already set this is nested. So
- // save the old name and create the nested name.
- if (!XarMemberName.empty()) {
- OldXarMemberName = XarMemberName;
- XarMemberName =
- (Twine("[") + XarMemberName + "]" + member_name).str();
- } else {
- OldXarMemberName = "";
- XarMemberName = member_name;
- }
- // See if this is could be a xar file (nested).
- if (member_size >= sizeof(struct xar_header)) {
-#if 0 // Useful for debugging.
- outs() << "could be a xar file: " << member_name << "\n";
-#endif
- memcpy((char *)&XarHeader, buffer, sizeof(struct xar_header));
- if (sys::IsLittleEndianHost)
- swapStruct(XarHeader);
- if (XarHeader.magic == XAR_HEADER_MAGIC)
- DumpBitcodeSection(O, buffer, member_size, verbose,
- PrintXarHeader, PrintXarFileHeaders,
- XarMemberName);
- }
- XarMemberName = OldXarMemberName;
- delete buffer;
- }
- }
- }
- }
-}
-#endif // defined(LLVM_HAVE_LIBXAR)
-
static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
if (O->is64Bit())
printObjc2_64bit_MetaData(O, verbose);
@@ -8047,16 +7629,13 @@
template <typename T>
static uint64_t read(StringRef Contents, ptrdiff_t Offset) {
- using llvm::support::little;
- using llvm::support::unaligned;
-
if (Offset + sizeof(T) > Contents.size()) {
outs() << "warning: attempt to read past end of buffer\n";
return T();
}
- uint64_t Val =
- support::endian::read<T, little, unaligned>(Contents.data() + Offset);
+ uint64_t Val = support::endian::read<T, llvm::endianness::little>(
+ Contents.data() + Offset);
return Val;
}
@@ -10554,9 +10133,9 @@
PrintMachHeader(file, Verbose);
}
-void MachODumper::printPrivateHeaders(bool OnlyFirst) {
+void MachODumper::printPrivateHeaders() {
printMachOFileHeader(&Obj);
- if (!OnlyFirst)
+ if (!FirstPrivateHeader)
printMachOLoadCommands(&Obj);
}
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOptID.h b/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOptID.h
index 65f6c60..fc90cb5 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOptID.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOptID.h
@@ -1,11 +1,11 @@
#ifndef LLVM_TOOLS_LLVM_OBJDUMP_OBJDUMP_OPT_ID_H
#define LLVM_TOOLS_LLVM_OBJDUMP_OBJDUMP_OPT_ID_H
+#include "llvm/Option/OptTable.h"
+
enum ObjdumpOptID {
OBJDUMP_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OBJDUMP_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OBJDUMP_, __VA_ARGS__),
#include "ObjdumpOpts.inc"
#undef OPTION
};
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td b/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td
index e3e7476..c1dec5c 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td
+++ b/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td
@@ -87,6 +87,11 @@
def : JoinedOrSeparate<["-"], "M">, Alias<disassembler_options_EQ>,
HelpText<"Alias for --disassembler-options=">;
+def disassembler_color_EQ : Joined<["--"], "disassembler-color=">,
+ MetaVarName<"mode">,
+ HelpText<"Enable or disable disassembler color output. "
+ "Valid options are \"on\", \"off\" and \"terminal\" (default)">;
+
def dynamic_reloc : Flag<["--"], "dynamic-reloc">,
HelpText<"Display the dynamic relocation entries in the file">;
def : Flag<["-"], "R">, Alias<dynamic_reloc>,
@@ -132,6 +137,9 @@
MetaVarName<"a1,+a2,-a3,...">,
HelpText<"Target specific attributes (--mattr=help for details)">;
+def mllvm : Separate<["-"], "mllvm">, HelpText<"Specify an argument to forward to LLVM's CommandLine library">, MetaVarName<"<arg>">;
+def : Joined<["-"], "mllvm=">, Alias<mllvm>;
+
def no_show_raw_insn : Flag<["--"], "no-show-raw-insn">,
HelpText<"When disassembling instructions, "
"do not print the instruction bytes.">;
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp b/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp
index b2fe56c..76da865 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp
@@ -436,7 +436,7 @@
OS << Delimiter << LineInfo.FunctionName;
// If demangling is successful, FunctionName will end with "()". Print it
// only if demangling did not run or was unsuccessful.
- if (!StringRef(LineInfo.FunctionName).endswith("()"))
+ if (!StringRef(LineInfo.FunctionName).ends_with("()"))
OS << "()";
OS << ":\n";
}
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp
index a1d767d..56c0847 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp
@@ -25,7 +25,7 @@
public:
WasmDumper(const WasmObjectFile &O) : Dumper(O), Obj(O) {}
- void printPrivateHeaders(bool MachOOnlyFirst) override;
+ void printPrivateHeaders() override;
};
} // namespace
@@ -34,7 +34,7 @@
return std::make_unique<WasmDumper>(Obj);
}
-void WasmDumper::printPrivateHeaders(bool) {
+void WasmDumper::printPrivateHeaders() {
outs() << "Program Header:\n";
outs() << "Version: 0x";
outs().write_hex(Obj.getHeader().Version);
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
index 87b1679..d9c00c0 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
@@ -32,7 +32,7 @@
class XCOFFDumper : public objdump::Dumper {
public:
XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {}
- void printPrivateHeaders(bool MachOOnlyFirst) override;
+ void printPrivateHeaders() override {}
};
} // namespace
@@ -41,10 +41,9 @@
return std::make_unique<XCOFFDumper>(Obj);
}
-void XCOFFDumper::printPrivateHeaders(bool) {}
-
Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,
const RelocationRef &Rel,
+ bool SymbolDescription,
SmallVectorImpl<char> &Result) {
symbol_iterator SymI = Rel.getSymbol();
if (SymI == Obj.symbol_end())
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h
index cf5b19f..0ba6ba4 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h
@@ -33,6 +33,7 @@
Error getXCOFFRelocationValueString(const object::XCOFFObjectFile &Obj,
const object::RelocationRef &RelRef,
+ bool SymbolDescription,
llvm::SmallVectorImpl<char> &Result);
void dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address,
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp
index bd45ed1..22b427f 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -24,13 +24,12 @@
#include "SourcePrinter.h"
#include "WasmDump.h"
#include "XCOFFDump.h"
-#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/BTF/BTFParser.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
@@ -72,7 +71,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/StringSaver.h"
@@ -85,6 +84,7 @@
#include <cctype>
#include <cstring>
#include <optional>
+#include <set>
#include <system_error>
#include <unordered_map>
#include <utility>
@@ -128,12 +128,8 @@
#undef PREFIX
static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, \
- METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OBJDUMP_##GROUP, \
- OBJDUMP_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) \
+ LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJDUMP_, __VA_ARGS__),
#include "ObjdumpOpts.inc"
#undef OPTION
};
@@ -149,9 +145,7 @@
enum OtoolOptID {
OTOOL_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OTOOL_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__),
#include "OtoolOpts.inc"
#undef OPTION
};
@@ -165,12 +159,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info OtoolInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, \
- METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OTOOL_##GROUP, \
- OTOOL_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__),
#include "OtoolOpts.inc"
#undef OPTION
};
@@ -187,6 +176,13 @@
#define DEBUG_TYPE "objdump"
+enum class ColorOutput {
+ Auto,
+ Enable,
+ Disable,
+ Invalid,
+};
+
static uint64_t AdjustVMA;
static bool AllHeaders;
static std::string ArchName;
@@ -199,6 +195,7 @@
static std::vector<std::string> DisassembleSymbols;
static bool DisassembleZeroes;
static std::vector<std::string> DisassemblerOptions;
+static ColorOutput DisassemblyColor;
DIDumpType objdump::DwarfDumpType;
static bool DynamicRelocations;
static bool FaultMapSection;
@@ -245,15 +242,21 @@
static StringRef ToolName;
std::unique_ptr<BuildIDFetcher> BIDFetcher;
-ExitOnError ExitOnErr;
+
+Dumper::Dumper(const object::ObjectFile &O) : O(O) {
+ WarningHandler = [this](const Twine &Msg) {
+ if (Warnings.insert(Msg.str()).second)
+ reportWarning(Msg, this->O.getFileName());
+ return Error::success();
+ };
+}
void Dumper::reportUniqueWarning(Error Err) {
reportUniqueWarning(toString(std::move(Err)));
}
void Dumper::reportUniqueWarning(const Twine &Msg) {
- if (Warnings.insert(StringRef(Msg.str())).second)
- reportWarning(Msg, O.getFileName());
+ cantFail(WarningHandler(Msg));
}
static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) {
@@ -420,6 +423,7 @@
}
static Error getRelocationValueString(const RelocationRef &Rel,
+ bool SymbolDescription,
SmallVectorImpl<char> &Result) {
const ObjectFile *Obj = Rel.getObject();
if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))
@@ -431,7 +435,8 @@
if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
return getMachORelocationValueString(MachO, Rel, Result);
if (auto *XCOFF = dyn_cast<XCOFFObjectFile>(Obj))
- return getXCOFFRelocationValueString(*XCOFF, Rel, Result);
+ return getXCOFFRelocationValueString(*XCOFF, Rel, SymbolDescription,
+ Result);
llvm_unreachable("unknown object file format");
}
@@ -516,11 +521,6 @@
return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ;
}
-static bool isMappingSymbol(const SymbolInfoTy &Sym) {
- return Sym.Name.startswith("$d") || Sym.Name.startswith("$x") ||
- Sym.Name.startswith("$a") || Sym.Name.startswith("$t");
-}
-
static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,
const RelocationRef &Rel, uint64_t Address,
bool Is64Bits) {
@@ -528,7 +528,7 @@
SmallString<16> Name;
SmallString<32> Val;
Rel.getTypeName(Name);
- if (Error E = getRelocationValueString(Rel, Val))
+ if (Error E = getRelocationValueString(Rel, SymbolDescription, Val))
reportError(std::move(E), FileName);
OS << (Is64Bits || !LeadingAddr ? "\t\t" : "\t\t\t");
if (LeadingAddr)
@@ -536,6 +536,22 @@
OS << Name << "\t" << Val;
}
+static void printBTFRelocation(formatted_raw_ostream &FOS, llvm::BTFParser &BTF,
+ object::SectionedAddress Address,
+ LiveVariablePrinter &LVP) {
+ const llvm::BTF::BPFFieldReloc *Reloc = BTF.findFieldReloc(Address);
+ if (!Reloc)
+ return;
+
+ SmallString<64> Val;
+ BTF.symbolize(Reloc, Val);
+ FOS << "\t\t";
+ if (LeadingAddr)
+ FOS << format("%016" PRIx64 ": ", Address.Address + AdjustVMA);
+ FOS << "CO-RE " << Val;
+ LVP.printAfterOtherLine(FOS, true);
+}
+
class PrettyPrinter {
public:
virtual ~PrettyPrinter() = default;
@@ -669,8 +685,9 @@
// using the .long directive, or .byte directive if fewer than 4 bytes
// remaining
if (Bytes.size() >= 4) {
- OS << format("\t.long 0x%08" PRIx32 " ",
- support::endian::read32<support::little>(Bytes.data()));
+ OS << format(
+ "\t.long 0x%08" PRIx32 " ",
+ support::endian::read32<llvm::endianness::little>(Bytes.data()));
OS.indent(42);
} else {
OS << format("\t.byte 0x%02" PRIx8, Bytes[0]);
@@ -767,12 +784,12 @@
OS << "\t<unknown>";
}
- void setInstructionEndianness(llvm::support::endianness Endianness) {
+ void setInstructionEndianness(llvm::endianness Endianness) {
InstructionEndianness = Endianness;
}
private:
- llvm::support::endianness InstructionEndianness = llvm::support::little;
+ llvm::endianness InstructionEndianness = llvm::endianness::little;
};
ARMPrettyPrinter ARMPrettyPrinterInst;
@@ -795,8 +812,8 @@
for (; Pos + 4 <= End; Pos += 4)
OS << ' '
<< format_hex_no_prefix(
- llvm::support::endian::read<uint32_t>(Bytes.data() + Pos,
- llvm::support::little),
+ llvm::support::endian::read<uint32_t>(
+ Bytes.data() + Pos, llvm::endianness::little),
8);
if (Pos < End) {
OS << ' ';
@@ -836,6 +853,105 @@
return AArch64PrettyPrinterInst;
}
}
+
+class DisassemblerTarget {
+public:
+ const Target *TheTarget;
+ std::unique_ptr<const MCSubtargetInfo> SubtargetInfo;
+ std::shared_ptr<MCContext> Context;
+ std::unique_ptr<MCDisassembler> DisAsm;
+ std::shared_ptr<MCInstrAnalysis> InstrAnalysis;
+ std::shared_ptr<MCInstPrinter> InstPrinter;
+ PrettyPrinter *Printer;
+
+ DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj,
+ StringRef TripleName, StringRef MCPU,
+ SubtargetFeatures &Features);
+ DisassemblerTarget(DisassemblerTarget &Other, SubtargetFeatures &Features);
+
+private:
+ MCTargetOptions Options;
+ std::shared_ptr<const MCRegisterInfo> RegisterInfo;
+ std::shared_ptr<const MCAsmInfo> AsmInfo;
+ std::shared_ptr<const MCInstrInfo> InstrInfo;
+ std::shared_ptr<MCObjectFileInfo> ObjectFileInfo;
+};
+
+DisassemblerTarget::DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj,
+ StringRef TripleName, StringRef MCPU,
+ SubtargetFeatures &Features)
+ : TheTarget(TheTarget),
+ Printer(&selectPrettyPrinter(Triple(TripleName))),
+ RegisterInfo(TheTarget->createMCRegInfo(TripleName)) {
+ if (!RegisterInfo)
+ reportError(Obj.getFileName(), "no register info for target " + TripleName);
+
+ // Set up disassembler.
+ AsmInfo.reset(TheTarget->createMCAsmInfo(*RegisterInfo, TripleName, Options));
+ if (!AsmInfo)
+ reportError(Obj.getFileName(), "no assembly info for target " + TripleName);
+
+ SubtargetInfo.reset(
+ TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
+ if (!SubtargetInfo)
+ reportError(Obj.getFileName(),
+ "no subtarget info for target " + TripleName);
+ InstrInfo.reset(TheTarget->createMCInstrInfo());
+ if (!InstrInfo)
+ reportError(Obj.getFileName(),
+ "no instruction info for target " + TripleName);
+ Context =
+ std::make_shared<MCContext>(Triple(TripleName), AsmInfo.get(),
+ RegisterInfo.get(), SubtargetInfo.get());
+
+ // FIXME: for now initialize MCObjectFileInfo with default values
+ ObjectFileInfo.reset(
+ TheTarget->createMCObjectFileInfo(*Context, /*PIC=*/false));
+ Context->setObjectFileInfo(ObjectFileInfo.get());
+
+ DisAsm.reset(TheTarget->createMCDisassembler(*SubtargetInfo, *Context));
+ if (!DisAsm)
+ reportError(Obj.getFileName(), "no disassembler for target " + TripleName);
+
+ InstrAnalysis.reset(TheTarget->createMCInstrAnalysis(InstrInfo.get()));
+
+ int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
+ InstPrinter.reset(TheTarget->createMCInstPrinter(Triple(TripleName),
+ AsmPrinterVariant, *AsmInfo,
+ *InstrInfo, *RegisterInfo));
+ if (!InstPrinter)
+ reportError(Obj.getFileName(),
+ "no instruction printer for target " + TripleName);
+ InstPrinter->setPrintImmHex(PrintImmHex);
+ InstPrinter->setPrintBranchImmAsAddress(true);
+ InstPrinter->setSymbolizeOperands(SymbolizeOperands);
+ InstPrinter->setMCInstrAnalysis(InstrAnalysis.get());
+
+ switch (DisassemblyColor) {
+ case ColorOutput::Enable:
+ InstPrinter->setUseColor(true);
+ break;
+ case ColorOutput::Auto:
+ InstPrinter->setUseColor(outs().has_colors());
+ break;
+ case ColorOutput::Disable:
+ case ColorOutput::Invalid:
+ InstPrinter->setUseColor(false);
+ break;
+ };
+}
+
+DisassemblerTarget::DisassemblerTarget(DisassemblerTarget &Other,
+ SubtargetFeatures &Features)
+ : TheTarget(Other.TheTarget),
+ SubtargetInfo(TheTarget->createMCSubtargetInfo(TripleName, MCPU,
+ Features.getString())),
+ Context(Other.Context),
+ DisAsm(TheTarget->createMCDisassembler(*SubtargetInfo, *Context)),
+ InstrAnalysis(Other.InstrAnalysis), InstPrinter(Other.InstPrinter),
+ Printer(Other.Printer), RegisterInfo(Other.RegisterInfo),
+ AsmInfo(Other.AsmInfo), InstrInfo(Other.InstrInfo),
+ ObjectFileInfo(Other.ObjectFileInfo) {}
} // namespace
static uint8_t getElfSymbolType(const ObjectFile &Obj, const SymbolRef &Sym) {
@@ -1052,8 +1168,8 @@
ArrayRef<uint8_t> Bytes,
ArrayRef<MappingSymbolPair> MappingSymbols,
const MCSubtargetInfo &STI, raw_ostream &OS) {
- support::endianness Endian =
- Obj.isLittleEndian() ? support::little : support::big;
+ llvm::endianness Endian =
+ Obj.isLittleEndian() ? llvm::endianness::little : llvm::endianness::big;
size_t Start = OS.tell();
OS << format("%8" PRIx64 ": ", SectionAddr + Index);
if (Index + 4 <= End) {
@@ -1112,7 +1228,8 @@
}
SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj,
- const SymbolRef &Symbol) {
+ const SymbolRef &Symbol,
+ bool IsMappingSymbol) {
const StringRef FileName = Obj.getFileName();
const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
const StringRef Name = unwrapOrError(Symbol.getName(), FileName);
@@ -1124,30 +1241,79 @@
const uint32_t SymbolIndex = XCOFFObj.getSymbolIndex(SymbolDRI.p);
std::optional<XCOFF::StorageMappingClass> Smc =
getXCOFFSymbolCsectSMC(XCOFFObj, Symbol);
- return SymbolInfoTy(Addr, Name, Smc, SymbolIndex,
+ return SymbolInfoTy(Smc, Addr, Name, SymbolIndex,
isLabel(XCOFFObj, Symbol));
} else if (Obj.isXCOFF()) {
const SymbolRef::Type SymType = unwrapOrError(Symbol.getType(), FileName);
- return SymbolInfoTy(Addr, Name, SymType, true);
- } else
- return SymbolInfoTy(Addr, Name,
- Obj.isELF() ? getElfSymbolType(Obj, Symbol)
- : (uint8_t)ELF::STT_NOTYPE);
+ return SymbolInfoTy(Addr, Name, SymType, /*IsMappingSymbol=*/false,
+ /*IsXCOFF=*/true);
+ } else {
+ uint8_t Type =
+ Obj.isELF() ? getElfSymbolType(Obj, Symbol) : (uint8_t)ELF::STT_NOTYPE;
+ return SymbolInfoTy(Addr, Name, Type, IsMappingSymbol);
+ }
}
static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj,
const uint64_t Addr, StringRef &Name,
uint8_t Type) {
if (Obj.isXCOFF() && (SymbolDescription || TracebackTable))
- return SymbolInfoTy(Addr, Name, std::nullopt, std::nullopt, false);
+ return SymbolInfoTy(std::nullopt, Addr, Name, std::nullopt, false);
else
return SymbolInfoTy(Addr, Name, Type);
}
-static void
-collectBBAddrMapLabels(const std::unordered_map<uint64_t, BBAddrMap> &AddrToBBAddrMap,
- uint64_t SectionAddr, uint64_t Start, uint64_t End,
- std::unordered_map<uint64_t, std::vector<std::string>> &Labels) {
+struct BBAddrMapLabel {
+ std::string BlockLabel;
+ std::string PGOAnalysis;
+};
+
+static std::string constructPGOLabelString(const PGOAnalysisMap &PGOMap,
+ size_t BBEntryIndex) {
+ std::string PGOString;
+ raw_string_ostream PGOSS(PGOString);
+
+ PGOSS << " (";
+ if (PGOMap.FeatEnable.FuncEntryCount && BBEntryIndex == 0) {
+ PGOSS << "Entry count: " << Twine(PGOMap.FuncEntryCount);
+ if (PGOMap.FeatEnable.BBFreq || PGOMap.FeatEnable.BrProb) {
+ PGOSS << ", ";
+ }
+ }
+
+ if (PGOMap.FeatEnable.BBFreq || PGOMap.FeatEnable.BrProb) {
+ assert(BBEntryIndex < PGOMap.BBEntries.size() &&
+ "Expected PGOAnalysisMap and BBAddrMap to have the same entires");
+ const PGOAnalysisMap::PGOBBEntry &PGOBBEntry =
+ PGOMap.BBEntries[BBEntryIndex];
+
+ if (PGOMap.FeatEnable.BBFreq) {
+ PGOSS << "Frequency: " << Twine(PGOBBEntry.BlockFreq.getFrequency());
+ if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) {
+ PGOSS << ", ";
+ }
+ }
+ if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) {
+ PGOSS << "Successors: ";
+ interleaveComma(
+ PGOBBEntry.Successors, PGOSS,
+ [&PGOSS](const PGOAnalysisMap::PGOBBEntry::SuccessorEntry &SE) {
+ PGOSS << "BB" << SE.ID << ":";
+ PGOSS.write_hex(SE.Prob.getNumerator());
+ });
+ }
+ }
+ PGOSS << ")";
+
+ return PGOString;
+}
+
+static void collectBBAddrMapLabels(
+ const std::unordered_map<uint64_t, BBAddrMap> &AddrToBBAddrMap,
+ const std::unordered_map<uint64_t, PGOAnalysisMap> &AddrToPGOAnalysisMap,
+ uint64_t SectionAddr, uint64_t Start, uint64_t End,
+ std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> &Labels,
+ const StringRef FileName) {
if (AddrToBBAddrMap.empty())
return;
Labels.clear();
@@ -1156,28 +1322,44 @@
auto Iter = AddrToBBAddrMap.find(StartAddress);
if (Iter == AddrToBBAddrMap.end())
return;
- for (const BBAddrMap::BBEntry &BBEntry : Iter->second.BBEntries) {
- uint64_t BBAddress = BBEntry.Offset + Iter->second.Addr;
+ auto PGOIter = AddrToPGOAnalysisMap.find(StartAddress);
+
+ for (size_t I = 0; I < Iter->second.getBBEntries().size(); ++I) {
+ const BBAddrMap::BBEntry &BBEntry = Iter->second.getBBEntries()[I];
+ uint64_t BBAddress = BBEntry.Offset + Iter->second.getFunctionAddress();
if (BBAddress >= EndAddress)
continue;
- Labels[BBAddress].push_back(("BB" + Twine(BBEntry.ID)).str());
+
+ std::string LabelString = ("BB" + Twine(BBEntry.ID)).str();
+ std::string PGOString;
+
+ if (PGOIter != AddrToPGOAnalysisMap.end())
+ PGOString = constructPGOLabelString(PGOIter->second, I);
+
+ Labels[BBAddress].push_back({LabelString, PGOString});
}
}
-static void collectLocalBranchTargets(
- ArrayRef<uint8_t> Bytes, const MCInstrAnalysis *MIA, MCDisassembler *DisAsm,
- MCInstPrinter *IP, const MCSubtargetInfo *STI, uint64_t SectionAddr,
- uint64_t Start, uint64_t End, std::unordered_map<uint64_t, std::string> &Labels) {
+static void
+collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, MCInstrAnalysis *MIA,
+ MCDisassembler *DisAsm, MCInstPrinter *IP,
+ const MCSubtargetInfo *STI, uint64_t SectionAddr,
+ uint64_t Start, uint64_t End,
+ std::unordered_map<uint64_t, std::string> &Labels) {
// So far only supports PowerPC and X86.
- if (!STI->getTargetTriple().isPPC() && !STI->getTargetTriple().isX86())
+ const bool isPPC = STI->getTargetTriple().isPPC();
+ if (!isPPC && !STI->getTargetTriple().isX86())
return;
+ if (MIA)
+ MIA->resetState();
+
Labels.clear();
unsigned LabelCount = 0;
Start += SectionAddr;
End += SectionAddr;
- uint64_t Index = Start;
- while (Index < End) {
+ const bool isXCOFF = STI->getTargetTriple().isOSBinFormatXCOFF();
+ for (uint64_t Index = Start; Index < End;) {
// Disassemble a real instruction and record function-local branch labels.
MCInst Inst;
uint64_t Size;
@@ -1188,15 +1370,22 @@
Size = std::min<uint64_t>(ThisBytes.size(),
DisAsm->suggestBytesToSkip(ThisBytes, Index));
- if (Disassembled && MIA) {
- uint64_t Target;
- bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target);
- // On PowerPC, if the address of a branch is the same as the target, it
- // means that it's a function call. Do not mark the label for this case.
- if (TargetKnown && (Target >= Start && Target < End) &&
- !Labels.count(Target) &&
- !(STI->getTargetTriple().isPPC() && Target == Index))
- Labels[Target] = ("L" + Twine(LabelCount++)).str();
+ if (MIA) {
+ if (Disassembled) {
+ uint64_t Target;
+ bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target);
+ if (TargetKnown && (Target >= Start && Target < End) &&
+ !Labels.count(Target)) {
+ // On PowerPC and AIX, a function call is encoded as a branch to 0.
+ // On other PowerPC platforms (ELF), a function call is encoded as
+ // a branch to self. Do not add a label for these cases.
+ if (!(isPPC &&
+ ((Target == 0 && isXCOFF) || (Target == Index && !isXCOFF))))
+ Labels[Target] = ("L" + Twine(LabelCount++)).str();
+ }
+ MIA->updateState(Inst, Index);
+ } else
+ MIA->resetState();
}
Index += Size;
}
@@ -1326,29 +1515,48 @@
return std::move(*DebugBinary);
}
-static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
- const ObjectFile &DbgObj, MCContext &Ctx,
- MCDisassembler *PrimaryDisAsm,
- MCDisassembler *SecondaryDisAsm,
- const MCInstrAnalysis *MIA, MCInstPrinter *IP,
- const MCSubtargetInfo *PrimarySTI,
- const MCSubtargetInfo *SecondarySTI,
- PrettyPrinter &PIP, SourcePrinter &SP,
- bool InlineRelocs) {
- const MCSubtargetInfo *STI = PrimarySTI;
- MCDisassembler *DisAsm = PrimaryDisAsm;
+static void
+disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
+ DisassemblerTarget &PrimaryTarget,
+ std::optional<DisassemblerTarget> &SecondaryTarget,
+ SourcePrinter &SP, bool InlineRelocs) {
+ DisassemblerTarget *DT = &PrimaryTarget;
bool PrimaryIsThumb = false;
- if (isArmElf(Obj))
- PrimaryIsThumb = STI->checkFeatures("+thumb-mode");
+ SmallVector<std::pair<uint64_t, uint64_t>, 0> CHPECodeMap;
+
+ if (SecondaryTarget) {
+ if (isArmElf(Obj)) {
+ PrimaryIsThumb =
+ PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode");
+ } else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) {
+ const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata();
+ if (CHPEMetadata && CHPEMetadata->CodeMapCount) {
+ uintptr_t CodeMapInt;
+ cantFail(COFFObj->getRvaPtr(CHPEMetadata->CodeMap, CodeMapInt));
+ auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt);
+
+ for (uint32_t i = 0; i < CHPEMetadata->CodeMapCount; ++i) {
+ if (CodeMap[i].getType() == chpe_range_type::Amd64 &&
+ CodeMap[i].Length) {
+ // Store x86_64 CHPE code ranges.
+ uint64_t Start = CodeMap[i].getStart() + COFFObj->getImageBase();
+ CHPECodeMap.emplace_back(Start, Start + CodeMap[i].Length);
+ }
+ }
+ llvm::sort(CHPECodeMap);
+ }
+ }
+ }
std::map<SectionRef, std::vector<RelocationRef>> RelocMap;
- if (InlineRelocs)
+ if (InlineRelocs || Obj.isXCOFF())
RelocMap = getRelocsMap(Obj);
bool Is64Bits = Obj.getBytesInAddress() > 4;
// Create a mapping from virtual address to symbol name. This is used to
// pretty print the symbols while disassembling.
std::map<SectionRef, SectionSymbolsTy> AllSymbols;
+ std::map<SectionRef, SmallVector<MappingSymbolPair, 0>> AllMappingSymbols;
SectionSymbolsTy AbsoluteSymbols;
const StringRef FileName = Obj.getFileName();
const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&Obj);
@@ -1361,14 +1569,39 @@
if (NameOrErr->empty() && !(Obj.isXCOFF() && SymbolDescription))
continue;
- if (Obj.isELF() && getElfSymbolType(Obj, Symbol) == ELF::STT_SECTION)
+ if (Obj.isELF() &&
+ (cantFail(Symbol.getFlags()) & SymbolRef::SF_FormatSpecific)) {
+ // Symbol is intended not to be displayed by default (STT_FILE,
+ // STT_SECTION, or a mapping symbol). Ignore STT_SECTION symbols. We will
+ // synthesize a section symbol if no symbol is defined at offset 0.
+ //
+ // For a mapping symbol, store it within both AllSymbols and
+ // AllMappingSymbols. If --show-all-symbols is unspecified, its label will
+ // not be printed in disassembly listing.
+ if (getElfSymbolType(Obj, Symbol) != ELF::STT_SECTION &&
+ hasMappingSymbols(Obj)) {
+ section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
+ if (SecI != Obj.section_end()) {
+ uint64_t SectionAddr = SecI->getAddress();
+ uint64_t Address = cantFail(Symbol.getAddress());
+ StringRef Name = *NameOrErr;
+ if (Name.consume_front("$") && Name.size() &&
+ strchr("adtx", Name[0])) {
+ AllMappingSymbols[*SecI].emplace_back(Address - SectionAddr,
+ Name[0]);
+ AllSymbols[*SecI].push_back(
+ createSymbolInfo(Obj, Symbol, /*MappingSymbol=*/true));
+ }
+ }
+ }
continue;
+ }
if (MachO) {
// __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special
// symbols that support MachO header introspection. They do not bind to
// code locations and are irrelevant for disassembly.
- if (NameOrErr->startswith("__mh_") && NameOrErr->endswith("_header"))
+ if (NameOrErr->starts_with("__mh_") && NameOrErr->ends_with("_header"))
continue;
// Don't ask a Mach-O STAB symbol for its section unless you know that
// STAB symbol's section field refers to a valid section index. Otherwise
@@ -1450,7 +1683,7 @@
llvm::stable_sort(AbsoluteSymbols);
std::unique_ptr<DWARFContext> DICtx;
- LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI);
+ LiveVariablePrinter LVP(*DT->Context->getRegisterInfo(), *DT->SubtargetInfo);
if (DbgVariables != DVDisabled) {
DICtx = DWARFContext::create(DbgObj);
@@ -1461,18 +1694,24 @@
LLVM_DEBUG(LVP.dump());
std::unordered_map<uint64_t, BBAddrMap> AddrToBBAddrMap;
+ std::unordered_map<uint64_t, PGOAnalysisMap> AddrToPGOAnalysisMap;
auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex =
std::nullopt) {
AddrToBBAddrMap.clear();
if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {
- auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex);
+ std::vector<PGOAnalysisMap> PGOAnalyses;
+ auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex, &PGOAnalyses);
if (!BBAddrMapsOrErr) {
reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName());
return;
}
- for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr)
- AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr,
- std::move(FunctionBBAddrMap));
+ for (const auto &[FunctionBBAddrMap, FunctionPGOAnalysis] :
+ zip_equal(*std::move(BBAddrMapsOrErr), std::move(PGOAnalyses))) {
+ uint64_t Addr = FunctionBBAddrMap.Addr;
+ AddrToBBAddrMap.emplace(Addr, std::move(FunctionBBAddrMap));
+ if (FunctionPGOAnalysis.FeatEnable.anyEnabled())
+ AddrToPGOAnalysisMap.emplace(Addr, std::move(FunctionPGOAnalysis));
+ }
}
};
@@ -1481,6 +1720,16 @@
if (SymbolizeOperands && !Obj.isRelocatableObject())
ReadBBAddrMap();
+ std::optional<llvm::BTFParser> BTF;
+ if (InlineRelocs && BTFParser::hasBTFSections(Obj)) {
+ BTF.emplace();
+ BTFParser::ParseOptions Opts = {};
+ Opts.LoadTypes = true;
+ Opts.LoadRelocs = true;
+ if (Error E = BTF->parse(Obj, Opts))
+ WithColor::defaultErrorHandler(std::move(E));
+ }
+
for (const SectionRef &Section : ToolSectionFilter(Obj)) {
if (FilterSections.empty() && !DisassembleAll &&
(!Section.isText() || Section.isVirtual()))
@@ -1498,22 +1747,7 @@
// Get the list of all the symbols in this section.
SectionSymbolsTy &Symbols = AllSymbols[Section];
- std::vector<MappingSymbolPair> MappingSymbols;
- if (hasMappingSymbols(Obj)) {
- for (const auto &Symb : Symbols) {
- uint64_t Address = Symb.Addr;
- StringRef Name = Symb.Name;
- if (Name.startswith("$d"))
- MappingSymbols.emplace_back(Address - SectionAddr, 'd');
- if (Name.startswith("$x"))
- MappingSymbols.emplace_back(Address - SectionAddr, 'x');
- if (Name.startswith("$a"))
- MappingSymbols.emplace_back(Address - SectionAddr, 'a');
- if (Name.startswith("$t"))
- MappingSymbols.emplace_back(Address - SectionAddr, 't');
- }
- }
-
+ auto &MappingSymbols = AllMappingSymbols[Section];
llvm::sort(MappingSymbols);
ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(
@@ -1522,18 +1756,33 @@
std::vector<std::unique_ptr<std::string>> SynthesizedLabelNames;
if (Obj.isELF() && Obj.getArch() == Triple::amdgcn) {
// AMDGPU disassembler uses symbolizer for printing labels
- addSymbolizer(Ctx, TheTarget, TripleName, DisAsm, SectionAddr, Bytes,
- Symbols, SynthesizedLabelNames);
+ addSymbolizer(*DT->Context, DT->TheTarget, TripleName, DT->DisAsm.get(),
+ SectionAddr, Bytes, Symbols, SynthesizedLabelNames);
}
StringRef SegmentName = getSegmentName(MachO, Section);
StringRef SectionName = unwrapOrError(Section.getName(), Obj.getFileName());
// If the section has no symbol at the start, just insert a dummy one.
- if (Symbols.empty() || Symbols[0].Addr != 0) {
- Symbols.insert(Symbols.begin(),
- createDummySymbolInfo(Obj, SectionAddr, SectionName,
- Section.isText() ? ELF::STT_FUNC
- : ELF::STT_OBJECT));
+ // Without --show-all-symbols, also insert one if all symbols at the start
+ // are mapping symbols.
+ bool CreateDummy = Symbols.empty();
+ if (!CreateDummy) {
+ CreateDummy = true;
+ for (auto &Sym : Symbols) {
+ if (Sym.Addr != SectionAddr)
+ break;
+ if (!Sym.IsMappingSymbol || ShowAllSymbols)
+ CreateDummy = false;
+ }
+ }
+ if (CreateDummy) {
+ SymbolInfoTy Sym = createDummySymbolInfo(
+ Obj, SectionAddr, SectionName,
+ Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT);
+ if (Obj.isXCOFF())
+ Symbols.insert(Symbols.begin(), Sym);
+ else
+ Symbols.insert(llvm::lower_bound(Symbols, Sym), Sym);
}
SmallString<40> Comments;
@@ -1599,19 +1848,19 @@
// inside functions, for which STT_FUNC would be inaccurate.
//
// So here, we spot whether there's any non-data symbol present at all,
- // and only set the DisassembleAsData flag if there isn't. Also, we use
+ // and only set the DisassembleAsELFData flag if there isn't. Also, we use
// this distinction to inform the decision of which symbol to print at
// the head of the section, so that if we're printing code, we print a
// code-related symbol name to go with it.
- bool DisassembleAsData = false;
+ bool DisassembleAsELFData = false;
size_t DisplaySymIndex = SymbolsHere.size() - 1;
if (Obj.isELF() && !DisassembleAll && Section.isText()) {
- DisassembleAsData = true; // unless we find a code symbol below
+ DisassembleAsELFData = true; // unless we find a code symbol below
for (size_t i = 0; i < SymbolsHere.size(); ++i) {
uint8_t SymTy = SymbolsHere[i].Type;
if (SymTy != ELF::STT_OBJECT && SymTy != ELF::STT_COMMON) {
- DisassembleAsData = false;
+ DisassembleAsELFData = false;
DisplaySymIndex = i;
}
}
@@ -1634,7 +1883,7 @@
// disassembling this entire chunk of code.
if (!FoundAny)
continue;
- } else {
+ } else if (!SymbolsHere[DisplaySymIndex].IsMappingSymbol) {
// Otherwise, print whichever symbol at this location is last in the
// Symbols array, because that array is pre-sorted in a way intended to
// correlate with priority of which symbol to display.
@@ -1678,8 +1927,7 @@
outs() << SectionName << ":\n";
}
- outs() << '\n';
-
+ bool PrintedLabel = false;
for (size_t i = 0; i < SymbolsHere.size(); ++i) {
if (!SymsToPrint[i])
continue;
@@ -1687,6 +1935,10 @@
const SymbolInfoTy &Symbol = SymbolsHere[i];
const StringRef SymbolName = SymNamesHere[i];
+ if (!PrintedLabel) {
+ outs() << '\n';
+ PrintedLabel = true;
+ }
if (LeadingAddr)
outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
SectionAddr + Start + VMAAdjustment);
@@ -1716,9 +1968,9 @@
for (size_t SHI = 0; SHI < SymbolsHere.size(); ++SHI) {
SymbolInfoTy Symbol = SymbolsHere[SHI];
- auto Status =
- DisAsm->onSymbolStart(Symbol, Size, Bytes.slice(Start, End - Start),
- SectionAddr + Start, CommentStream);
+ auto Status = DT->DisAsm->onSymbolStart(
+ Symbol, Size, Bytes.slice(Start, End - Start), SectionAddr + Start,
+ CommentStream);
if (!Status) {
// If onSymbolStart returns std::nullopt, that means it didn't trigger
@@ -1743,7 +1995,7 @@
// distance to the next symbol, and sometimes it will be just a
// prologue and we should start disassembling instructions from where
// it left off.
- outs() << Ctx.getAsmInfo()->getCommentString()
+ outs() << DT->Context->getAsmInfo()->getCommentString()
<< " error in decoding " << SymNamesHere[SHI]
<< " : decoding failed region as bytes.\n";
for (uint64_t I = 0; I < Size; ++I) {
@@ -1759,12 +2011,19 @@
if (SectionAddr < StartAddress)
Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);
- if (DisassembleAsData) {
+ if (DisassembleAsELFData) {
dumpELFData(SectionAddr, Index, End, Bytes);
Index = End;
continue;
}
+ // Skip relocations from symbols that are not dumped.
+ for (; RelCur != RelEnd; ++RelCur) {
+ uint64_t Offset = RelCur->getOffset() - RelAdjustment;
+ if (Index <= Offset)
+ break;
+ }
+
bool DumpARMELFData = false;
bool DumpTracebackTableForXCOFFFunction =
Obj.isXCOFF() && Section.isText() && TracebackTable &&
@@ -1773,16 +2032,31 @@
formatted_raw_ostream FOS(outs());
+ // FIXME: Workaround for bug in formatted_raw_ostream. Color escape codes
+ // are (incorrectly) written directly to the unbuffered raw_ostream
+ // wrapped by the formatted_raw_ostream.
+ if (DisassemblyColor == ColorOutput::Enable ||
+ DisassemblyColor == ColorOutput::Auto)
+ FOS.SetUnbuffered();
+
std::unordered_map<uint64_t, std::string> AllLabels;
- std::unordered_map<uint64_t, std::vector<std::string>> BBAddrMapLabels;
+ std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels;
if (SymbolizeOperands) {
- collectLocalBranchTargets(Bytes, MIA, DisAsm, IP, PrimarySTI,
+ collectLocalBranchTargets(Bytes, DT->InstrAnalysis.get(),
+ DT->DisAsm.get(), DT->InstPrinter.get(),
+ PrimaryTarget.SubtargetInfo.get(),
SectionAddr, Index, End, AllLabels);
- collectBBAddrMapLabels(AddrToBBAddrMap, SectionAddr, Index, End,
- BBAddrMapLabels);
+ collectBBAddrMapLabels(AddrToBBAddrMap, AddrToPGOAnalysisMap,
+ SectionAddr, Index, End, BBAddrMapLabels,
+ FileName);
}
+ if (DT->InstrAnalysis)
+ DT->InstrAnalysis->resetState();
+
while (Index < End) {
+ uint64_t RelOffset;
+
// ARM and AArch64 ELF binaries can interleave data and text in the
// same section. We rely on the markers introduced to understand what
// we need to dump. If the data marker is within a function, it is
@@ -1790,20 +2064,56 @@
if (!MappingSymbols.empty()) {
char Kind = getMappingSymbolKind(MappingSymbols, Index);
DumpARMELFData = Kind == 'd';
- if (SecondarySTI) {
+ if (SecondaryTarget) {
if (Kind == 'a') {
- STI = PrimaryIsThumb ? SecondarySTI : PrimarySTI;
- DisAsm = PrimaryIsThumb ? SecondaryDisAsm : PrimaryDisAsm;
+ DT = PrimaryIsThumb ? &*SecondaryTarget : &PrimaryTarget;
} else if (Kind == 't') {
- STI = PrimaryIsThumb ? PrimarySTI : SecondarySTI;
- DisAsm = PrimaryIsThumb ? PrimaryDisAsm : SecondaryDisAsm;
+ DT = PrimaryIsThumb ? &PrimaryTarget : &*SecondaryTarget;
}
}
+ } else if (!CHPECodeMap.empty()) {
+ uint64_t Address = SectionAddr + Index;
+ auto It = partition_point(
+ CHPECodeMap,
+ [Address](const std::pair<uint64_t, uint64_t> &Entry) {
+ return Entry.first <= Address;
+ });
+ if (It != CHPECodeMap.begin() && Address < (It - 1)->second) {
+ DT = &*SecondaryTarget;
+ } else {
+ DT = &PrimaryTarget;
+ // X64 disassembler range may have left Index unaligned, so
+ // make sure that it's aligned when we switch back to ARM64
+ // code.
+ Index = llvm::alignTo(Index, 4);
+ if (Index >= End)
+ break;
+ }
}
+ auto findRel = [&]() {
+ while (RelCur != RelEnd) {
+ RelOffset = RelCur->getOffset() - RelAdjustment;
+ // If this relocation is hidden, skip it.
+ if (getHidden(*RelCur) || SectionAddr + RelOffset < StartAddress) {
+ ++RelCur;
+ continue;
+ }
+
+ // Stop when RelCur's offset is past the disassembled
+ // instruction/data.
+ if (RelOffset >= Index + Size)
+ return false;
+ if (RelOffset >= Index)
+ return true;
+ ++RelCur;
+ }
+ return false;
+ };
+
if (DumpARMELFData) {
Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
- MappingSymbols, *STI, FOS);
+ MappingSymbols, *DT->SubtargetInfo, FOS);
} else {
// When -z or --disassemble-zeroes are given we always dissasemble
// them. Otherwise we might want to skip zero bytes we see.
@@ -1811,7 +2121,7 @@
uint64_t MaxOffset = End - Index;
// For --reloc: print zero blocks patched by relocations, so that
// relocations can be shown in the dump.
- if (RelCur != RelEnd)
+ if (InlineRelocs && RelCur != RelEnd)
MaxOffset = std::min(RelCur->getOffset() - RelAdjustment - Index,
MaxOffset);
@@ -1827,8 +2137,8 @@
doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) {
dumpTracebackTable(Bytes.slice(Index),
SectionAddr + Index + VMAAdjustment, FOS,
- SectionAddr + End + VMAAdjustment, *STI,
- cast<XCOFFObjectFile>(&Obj));
+ SectionAddr + End + VMAAdjustment,
+ *DT->SubtargetInfo, cast<XCOFFObjectFile>(&Obj));
Index = End;
continue;
}
@@ -1836,8 +2146,9 @@
// Print local label if there's any.
auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index);
if (Iter1 != BBAddrMapLabels.end()) {
- for (StringRef Label : Iter1->second)
- FOS << "<" << Label << ">:\n";
+ for (const auto &BBLabel : Iter1->second)
+ FOS << "<" << BBLabel.BlockLabel << ">" << BBLabel.PGOAnalysis
+ << ":\n";
} else {
auto Iter2 = AllLabels.find(SectionAddr + Index);
if (Iter2 != AllLabels.end())
@@ -1849,39 +2160,43 @@
MCInst Inst;
ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index);
uint64_t ThisAddr = SectionAddr + Index;
- bool Disassembled = DisAsm->getInstruction(Inst, Size, ThisBytes,
- ThisAddr, CommentStream);
+ bool Disassembled = DT->DisAsm->getInstruction(
+ Inst, Size, ThisBytes, ThisAddr, CommentStream);
if (Size == 0)
Size = std::min<uint64_t>(
ThisBytes.size(),
- DisAsm->suggestBytesToSkip(ThisBytes, ThisAddr));
+ DT->DisAsm->suggestBytesToSkip(ThisBytes, ThisAddr));
LVP.update({Index, Section.getIndex()},
{Index + Size, Section.getIndex()}, Index + Size != End);
- IP->setCommentStream(CommentStream);
+ DT->InstPrinter->setCommentStream(CommentStream);
- PIP.printInst(
- *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
+ DT->Printer->printInst(
+ *DT->InstPrinter, Disassembled ? &Inst : nullptr,
+ Bytes.slice(Index, Size),
{SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS,
- "", *STI, &SP, Obj.getFileName(), &Rels, LVP);
+ "", *DT->SubtargetInfo, &SP, Obj.getFileName(), &Rels, LVP);
- IP->setCommentStream(llvm::nulls());
+ DT->InstPrinter->setCommentStream(llvm::nulls());
- // If disassembly has failed, avoid analysing invalid/incomplete
- // instruction information. Otherwise, try to resolve the target
- // address (jump target or memory operand address) and print it on the
+ // If disassembly succeeds, we try to resolve the target address
+ // (jump target or memory operand address) and print it to the
// right of the instruction.
- if (Disassembled && MIA) {
- // Branch targets are printed just after the instructions.
+ //
+ // Otherwise, we don't print anything else so that we avoid
+ // analyzing invalid or incomplete instruction information.
+ if (Disassembled && DT->InstrAnalysis) {
llvm::raw_ostream *TargetOS = &FOS;
uint64_t Target;
- bool PrintTarget =
- MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target);
- if (!PrintTarget)
+ bool PrintTarget = DT->InstrAnalysis->evaluateBranch(
+ Inst, SectionAddr + Index, Size, Target);
+
+ if (!PrintTarget) {
if (std::optional<uint64_t> MaybeTarget =
- MIA->evaluateMemoryOperandAddress(
- Inst, STI, SectionAddr + Index, Size)) {
+ DT->InstrAnalysis->evaluateMemoryOperandAddress(
+ Inst, DT->SubtargetInfo.get(), SectionAddr + Index,
+ Size)) {
Target = *MaybeTarget;
PrintTarget = true;
// Do not print real address when symbolizing.
@@ -1891,6 +2206,8 @@
*TargetOS << "0x" << Twine::utohexstr(Target);
}
}
+ }
+
if (PrintTarget) {
// In a relocatable object, the target's section must reside in
// the same section as the call instruction or it is accessed
@@ -1900,7 +2217,8 @@
// In that case, locate the section(s) containing the target
// address and find the symbol in one of those, if possible.
//
- // N.B. We don't walk the relocations in the relocatable case yet.
+ // N.B. Except for XCOFF, we don't walk the relocations in the
+ // relocatable case yet.
std::vector<const SectionSymbolsTy *> TargetSectionSymbols;
if (!Obj.isRelocatableObject()) {
auto It = llvm::partition_point(
@@ -1937,7 +2255,7 @@
--It;
// Skip mapping symbols to avoid possible ambiguity as they
// do not allow uniquely identifying the target address.
- if (!hasMappingSymbols(Obj) || !isMappingSymbol(*It)) {
+ if (!It->IsMappingSymbol) {
TargetSym = &*It;
break;
}
@@ -1946,22 +2264,68 @@
break;
}
+ // Branch targets are printed just after the instructions.
// Print the labels corresponding to the target if there's any.
bool BBAddrMapLabelAvailable = BBAddrMapLabels.count(Target);
bool LabelAvailable = AllLabels.count(Target);
+
if (TargetSym != nullptr) {
uint64_t TargetAddress = TargetSym->Addr;
uint64_t Disp = Target - TargetAddress;
std::string TargetName = Demangle ? demangle(TargetSym->Name)
: TargetSym->Name.str();
+ bool RelFixedUp = false;
+ SmallString<32> Val;
*TargetOS << " <";
- if (!Disp) {
- // Always Print the binary symbol precisely corresponding to
- // the target address.
+ // On XCOFF, we use relocations, even without -r, so we
+ // can print the correct name for an extern function call.
+ if (Obj.isXCOFF() && findRel()) {
+ // Check for possible branch relocations and
+ // branches to fixup code.
+ bool BranchRelocationType = true;
+ XCOFF::RelocationType RelocType;
+ if (Obj.is64Bit()) {
+ const XCOFFRelocation64 *Reloc =
+ reinterpret_cast<XCOFFRelocation64 *>(
+ RelCur->getRawDataRefImpl().p);
+ RelFixedUp = Reloc->isFixupIndicated();
+ RelocType = Reloc->Type;
+ } else {
+ const XCOFFRelocation32 *Reloc =
+ reinterpret_cast<XCOFFRelocation32 *>(
+ RelCur->getRawDataRefImpl().p);
+ RelFixedUp = Reloc->isFixupIndicated();
+ RelocType = Reloc->Type;
+ }
+ BranchRelocationType =
+ RelocType == XCOFF::R_BA || RelocType == XCOFF::R_BR ||
+ RelocType == XCOFF::R_RBA || RelocType == XCOFF::R_RBR;
+
+ // If we have a valid relocation, try to print its
+ // corresponding symbol name. Multiple relocations on the
+ // same instruction are not handled.
+ // Branches to fixup code will have the RelFixedUp flag set in
+ // the RLD. For these instructions, we print the correct
+ // branch target, but print the referenced symbol as a
+ // comment.
+ if (Error E = getRelocationValueString(*RelCur, false, Val)) {
+ // If -r was used, this error will be printed later.
+ // Otherwise, we ignore the error and print what
+ // would have been printed without using relocations.
+ consumeError(std::move(E));
+ *TargetOS << TargetName;
+ RelFixedUp = false; // Suppress comment for RLD sym name
+ } else if (BranchRelocationType && !RelFixedUp)
+ *TargetOS << Val;
+ else
+ *TargetOS << TargetName;
+ if (Disp)
+ *TargetOS << "+0x" << Twine::utohexstr(Disp);
+ } else if (!Disp) {
*TargetOS << TargetName;
} else if (BBAddrMapLabelAvailable) {
- *TargetOS << BBAddrMapLabels[Target].front();
+ *TargetOS << BBAddrMapLabels[Target].front().BlockLabel;
} else if (LabelAvailable) {
*TargetOS << AllLabels[Target];
} else {
@@ -1970,8 +2334,15 @@
*TargetOS << TargetName << "+0x" << Twine::utohexstr(Disp);
}
*TargetOS << ">";
+ if (RelFixedUp && !InlineRelocs) {
+ // We have fixup code for a relocation. We print the
+ // referenced symbol as a comment.
+ *TargetOS << "\t# " << Val;
+ }
+
} else if (BBAddrMapLabelAvailable) {
- *TargetOS << " <" << BBAddrMapLabels[Target].front() << ">";
+ *TargetOS << " <" << BBAddrMapLabels[Target].front().BlockLabel
+ << ">";
} else if (LabelAvailable) {
*TargetOS << " <" << AllLabels[Target] << ">";
}
@@ -1980,44 +2351,35 @@
if (TargetOS == &CommentStream)
*TargetOS << "\n";
}
+
+ DT->InstrAnalysis->updateState(Inst, SectionAddr + Index);
+ } else if (!Disassembled && DT->InstrAnalysis) {
+ DT->InstrAnalysis->resetState();
}
}
- assert(Ctx.getAsmInfo());
- emitPostInstructionInfo(FOS, *Ctx.getAsmInfo(), *STI,
- CommentStream.str(), LVP);
+ assert(DT->Context->getAsmInfo());
+ emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(),
+ *DT->SubtargetInfo, CommentStream.str(), LVP);
Comments.clear();
- // Hexagon does this in pretty printer
- if (Obj.getArch() != Triple::hexagon) {
- // Print relocation for instruction and data.
- while (RelCur != RelEnd) {
- uint64_t Offset = RelCur->getOffset() - RelAdjustment;
- // If this relocation is hidden, skip it.
- if (getHidden(*RelCur) || SectionAddr + Offset < StartAddress) {
- ++RelCur;
- continue;
- }
+ if (BTF)
+ printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP);
- // Stop when RelCur's offset is past the disassembled
- // instruction/data. Note that it's possible the disassembled data
- // is not the complete data: we might see the relocation printed in
- // the middle of the data, but this matches the binutils objdump
- // output.
- if (Offset >= Index + Size)
- break;
-
+ // Hexagon handles relocs in pretty printer
+ if (InlineRelocs && Obj.getArch() != Triple::hexagon) {
+ while (findRel()) {
// When --adjust-vma is used, update the address printed.
if (RelCur->getSymbol() != Obj.symbol_end()) {
Expected<section_iterator> SymSI =
RelCur->getSymbol()->getSection();
if (SymSI && *SymSI != Obj.section_end() &&
shouldAdjustVA(**SymSI))
- Offset += AdjustVMA;
+ RelOffset += AdjustVMA;
}
printRelocation(FOS, Obj.getFileName(), *RelCur,
- SectionAddr + Offset, Is64Bits);
+ SectionAddr + RelOffset, Is64Bits);
LVP.printAfterOtherLine(FOS, true);
++RelCur;
}
@@ -2064,20 +2426,6 @@
Features.AddFeature("+all");
}
- std::unique_ptr<const MCRegisterInfo> MRI(
- TheTarget->createMCRegInfo(TripleName));
- if (!MRI)
- reportError(Obj->getFileName(),
- "no register info for target " + TripleName);
-
- // Set up disassembler.
- MCTargetOptions MCOptions;
- std::unique_ptr<const MCAsmInfo> AsmInfo(
- TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
- if (!AsmInfo)
- reportError(Obj->getFileName(),
- "no assembly info for target " + TripleName);
-
if (MCPU.empty())
MCPU = Obj->tryGetCPUName().value_or("").str();
@@ -2098,64 +2446,48 @@
if (Elf32BE && (Elf32BE->isRelocatableObject() ||
!(Elf32BE->getPlatformFlags() & ELF::EF_ARM_BE8))) {
Features.AddFeature("+big-endian-instructions");
- ARMPrettyPrinterInst.setInstructionEndianness(llvm::support::big);
+ ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::big);
} else {
- ARMPrettyPrinterInst.setInstructionEndianness(llvm::support::little);
+ ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::little);
}
}
- std::unique_ptr<const MCSubtargetInfo> STI(
- TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
- if (!STI)
- reportError(Obj->getFileName(),
- "no subtarget info for target " + TripleName);
- std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
- if (!MII)
- reportError(Obj->getFileName(),
- "no instruction info for target " + TripleName);
- MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
- // FIXME: for now initialize MCObjectFileInfo with default values
- std::unique_ptr<MCObjectFileInfo> MOFI(
- TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
- Ctx.setObjectFileInfo(MOFI.get());
-
- std::unique_ptr<MCDisassembler> DisAsm(
- TheTarget->createMCDisassembler(*STI, Ctx));
- if (!DisAsm)
- reportError(Obj->getFileName(), "no disassembler for target " + TripleName);
+ DisassemblerTarget PrimaryTarget(TheTarget, *Obj, TripleName, MCPU, Features);
// If we have an ARM object file, we need a second disassembler, because
// ARM CPUs have two different instruction sets: ARM mode, and Thumb mode.
// We use mapping symbols to switch between the two assemblers, where
// appropriate.
- std::unique_ptr<MCDisassembler> SecondaryDisAsm;
- std::unique_ptr<const MCSubtargetInfo> SecondarySTI;
- if (isArmElf(*Obj) && !STI->checkFeatures("+mclass")) {
- if (STI->checkFeatures("+thumb-mode"))
- Features.AddFeature("-thumb-mode");
- else
- Features.AddFeature("+thumb-mode");
- SecondarySTI.reset(TheTarget->createMCSubtargetInfo(TripleName, MCPU,
- Features.getString()));
- SecondaryDisAsm.reset(TheTarget->createMCDisassembler(*SecondarySTI, Ctx));
+ std::optional<DisassemblerTarget> SecondaryTarget;
+
+ if (isArmElf(*Obj)) {
+ if (!PrimaryTarget.SubtargetInfo->checkFeatures("+mclass")) {
+ if (PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode"))
+ Features.AddFeature("-thumb-mode");
+ else
+ Features.AddFeature("+thumb-mode");
+ SecondaryTarget.emplace(PrimaryTarget, Features);
+ }
+ } else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) {
+ const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata();
+ if (CHPEMetadata && CHPEMetadata->CodeMapCount) {
+ // Set up x86_64 disassembler for ARM64EC binaries.
+ Triple X64Triple(TripleName);
+ X64Triple.setArch(Triple::ArchType::x86_64);
+
+ std::string Error;
+ const Target *X64Target =
+ TargetRegistry::lookupTarget("", X64Triple, Error);
+ if (X64Target) {
+ SubtargetFeatures X64Features;
+ SecondaryTarget.emplace(X64Target, *Obj, X64Triple.getTriple(), "",
+ X64Features);
+ } else {
+ reportWarning(Error, Obj->getFileName());
+ }
+ }
}
- std::unique_ptr<const MCInstrAnalysis> MIA(
- TheTarget->createMCInstrAnalysis(MII.get()));
-
- int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
- std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
- if (!IP)
- reportError(Obj->getFileName(),
- "no instruction printer for target " + TripleName);
- IP->setPrintImmHex(PrintImmHex);
- IP->setPrintBranchImmAsAddress(true);
- IP->setSymbolizeOperands(SymbolizeOperands);
- IP->setMCInstrAnalysis(MIA.get());
-
- PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
-
const ObjectFile *DbgObj = Obj;
if (!FetchedBinary.getBinary() && !Obj->hasDebugInfo()) {
if (std::optional<OwningBinary<Binary>> DebugBinaryOpt =
@@ -2184,13 +2516,12 @@
SourcePrinter SP(DbgObj, TheTarget->getName());
for (StringRef Opt : DisassemblerOptions)
- if (!IP->applyTargetSpecificCLOption(Opt))
+ if (!PrimaryTarget.InstPrinter->applyTargetSpecificCLOption(Opt))
reportError(Obj->getFileName(),
"Unrecognized disassembler option: " + Opt);
- disassembleObject(TheTarget, *Obj, *DbgObj, Ctx, DisAsm.get(),
- SecondaryDisAsm.get(), MIA.get(), IP.get(), STI.get(),
- SecondarySTI.get(), PIP, SP, InlineRelocs);
+ disassembleObject(*Obj, *DbgObj, PrimaryTarget, SecondaryTarget, SP,
+ InlineRelocs);
}
void Dumper::printRelocations() {
@@ -2232,7 +2563,8 @@
if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))
continue;
Reloc.getTypeName(RelocName);
- if (Error E = getRelocationValueString(Reloc, ValueStr))
+ if (Error E =
+ getRelocationValueString(Reloc, SymbolDescription, ValueStr))
reportUniqueWarning(std::move(E));
outs() << format(Fmt.data(), Address) << " "
@@ -2411,6 +2743,9 @@
return;
}
uint64_t Address = *AddrOrErr;
+ section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
+ if (SecI != O.section_end() && shouldAdjustVA(*SecI))
+ Address += AdjustVMA;
if ((Address < StartAddress) || (Address > StopAddress))
return;
SymbolRef::Type Type =
@@ -2676,7 +3011,7 @@
outs() << FMP;
}
-void Dumper::printPrivateHeaders(bool) {
+void Dumper::printPrivateHeaders() {
reportError(O.getFileName(), "Invalid/Unsupported object file format");
}
@@ -2811,7 +3146,7 @@
if (FileHeaders)
printFileHeaders(O);
if (PrivateHeaders || FirstPrivateHeader)
- D.printPrivateHeaders(FirstPrivateHeader);
+ D.printPrivateHeaders();
if (SectionHeaders)
printSectionHeaders(*O);
if (SymbolTable)
@@ -3077,6 +3412,16 @@
if (DbgVariables == DVInvalid)
invalidArgValue(A);
}
+ if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_disassembler_color_EQ)) {
+ DisassemblyColor = StringSwitch<ColorOutput>(A->getValue())
+ .Case("on", ColorOutput::Enable)
+ .Case("off", ColorOutput::Disable)
+ .Case("terminal", ColorOutput::Auto)
+ .Default(ColorOutput::Invalid);
+ if (DisassemblyColor == ColorOutput::Invalid)
+ invalidArgValue(A);
+ }
+
parseIntArg(InputArgs, OBJDUMP_debug_vars_indent_EQ, DbgIndent);
parseMachOOptions(InputArgs);
@@ -3111,10 +3456,13 @@
DisassemblerOptions.push_back(V.str());
}
}
- if (AsmSyntax) {
- const char *Argv[] = {"llvm-objdump", AsmSyntax};
- llvm::cl::ParseCommandLineOptions(2, Argv);
- }
+ SmallVector<const char *> Args = {"llvm-objdump"};
+ for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_mllvm))
+ Args.push_back(A->getValue());
+ if (AsmSyntax)
+ Args.push_back(AsmSyntax);
+ if (Args.size() > 1)
+ llvm::cl::ParseCommandLineOptions(Args.size(), Args.data());
// Look up any provided build IDs, then append them to the input filenames.
for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) {
@@ -3132,9 +3480,8 @@
InputFilenames.push_back("a.out");
}
-int main(int argc, char **argv) {
+int llvm_objdump_main(int argc, char **argv, const llvm::ToolContext &) {
using namespace llvm;
- InitLLVM X(argc, argv);
ToolName = argv[0];
std::unique_ptr<CommonOptTable> T;
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h b/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h
index b3136f0..7778cf6 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -18,6 +18,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/FormattedStream.h"
+#include <functional>
#include <memory>
namespace llvm {
@@ -76,14 +77,17 @@
const object::ObjectFile &O;
StringSet<> Warnings;
+protected:
+ std::function<Error(const Twine &Msg)> WarningHandler;
+
public:
- Dumper(const object::ObjectFile &O) : O(O) {}
+ Dumper(const object::ObjectFile &O);
virtual ~Dumper() {}
void reportUniqueWarning(Error Err);
void reportUniqueWarning(const Twine &Msg);
- virtual void printPrivateHeaders(bool MachOOnlyFirst);
+ virtual void printPrivateHeaders();
virtual void printDynamicRelocations() {}
void printSymbolTable(StringRef ArchiveName,
StringRef ArchitectureName = StringRef(),
@@ -133,7 +137,8 @@
std::string getFileNameForError(const object::Archive::Child &C,
unsigned Index);
SymbolInfoTy createSymbolInfo(const object::ObjectFile &Obj,
- const object::SymbolRef &Symbol);
+ const object::SymbolRef &Symbol,
+ bool IsMappingSymbol = false);
unsigned getInstStartColumn(const MCSubtargetInfo &STI);
void printRawData(llvm::ArrayRef<uint8_t> Bytes, uint64_t Address,
llvm::formatted_raw_ostream &OS,
diff --git a/src/llvm-project/llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp b/src/llvm-project/llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp
index d952ea1..fcccf0e 100644
--- a/src/llvm-project/llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp
@@ -198,23 +198,9 @@
errs() << *argv[0] << ": -mtriple must be specified\n";
exit(1);
}
- Triple TargetTriple = Triple(Triple::normalize(TargetTripleStr));
-
- std::string Error;
- const Target *TheTarget =
- TargetRegistry::lookupTarget(codegen::getMArch(), TargetTriple, Error);
- if (!TheTarget) {
- errs() << *argv[0] << ": " << Error;
- exit(1);
- }
-
- TargetOptions Options =
- codegen::InitTargetOptionsFromCodeGenFlags(TargetTriple);
- TM.reset(TheTarget->createTargetMachine(
- TargetTriple.getTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(),
- Options, codegen::getExplicitRelocModel(),
- codegen::getExplicitCodeModel(), CodeGenOpt::Default));
- assert(TM && "Could not allocate target machine!");
+ ExitOnError ExitOnErr(std::string(*argv[0]) + ": error:");
+ TM = ExitOnErr(codegen::createTargetMachineForTriple(
+ Triple::normalize(TargetTripleStr)));
// Check that pass pipeline is specified and correct
//
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
index 447a9cb..5ce663e 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -1286,7 +1286,7 @@
return ContentsOrErr.takeError();
uint32_t Magic;
- BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little);
+ BinaryStreamReader Reader(*ContentsOrErr, llvm::endianness::little);
if (auto EC = Reader.readInteger(Magic))
return EC;
if (Magic != COFF::DEBUG_SECTION_MAGIC)
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
index a0c9530..6714a6a 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -17,8 +17,6 @@
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
-#include <string>
-
namespace llvm {
namespace object {
class COFFObjectFile;
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
index 3e57e31..ce9d659 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
@@ -66,9 +66,8 @@
}
Error ExplainOutputStyle::explainBinaryFile() {
- std::unique_ptr<BinaryByteStream> Stream =
- std::make_unique<BinaryByteStream>(File.unknown().getBuffer(),
- llvm::support::little);
+ std::unique_ptr<BinaryByteStream> Stream = std::make_unique<BinaryByteStream>(
+ File.unknown().getBuffer(), llvm::endianness::little);
switch (opts::explain::InputType) {
case opts::explain::InputFileType::DBIStream: {
DbiStream Dbi(std::move(Stream));
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
index 499f2a8..84b4a7e 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
@@ -13,8 +13,6 @@
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
-#include <string>
-
namespace llvm {
namespace pdb {
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
index 96c3d49..1beb2d2 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -358,6 +358,23 @@
return typesetItemList(GapStrs, 7, IndentLevel, ", ");
}
+static std::string formatJumpTableEntrySize(JumpTableEntrySize EntrySize) {
+ switch (EntrySize) {
+ RETURN_CASE(JumpTableEntrySize, Int8, "int8");
+ RETURN_CASE(JumpTableEntrySize, UInt8, "uin8");
+ RETURN_CASE(JumpTableEntrySize, Int16, "int16");
+ RETURN_CASE(JumpTableEntrySize, UInt16, "uint16");
+ RETURN_CASE(JumpTableEntrySize, Int32, "int32");
+ RETURN_CASE(JumpTableEntrySize, UInt32, "uint32");
+ RETURN_CASE(JumpTableEntrySize, Pointer, "pointer");
+ RETURN_CASE(JumpTableEntrySize, UInt8ShiftLeft, "uint8shl");
+ RETURN_CASE(JumpTableEntrySize, UInt16ShiftLeft, "uint16shl");
+ RETURN_CASE(JumpTableEntrySize, Int8ShiftLeft, "int8shl");
+ RETURN_CASE(JumpTableEntrySize, Int16ShiftLeft, "int16shl");
+ }
+ return formatUnknownEnum(EntrySize);
+}
+
Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) {
return visitSymbolBegin(Record, 0);
}
@@ -858,9 +875,24 @@
}
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ const char *Format;
+ switch (CVR.kind()) {
+ case S_CALLEES:
+ Format = "callee: {0}";
+ break;
+ case S_CALLERS:
+ Format = "caller: {0}";
+ break;
+ case S_INLINEES:
+ Format = "inlinee: {0}";
+ break;
+ default:
+ return llvm::make_error<CodeViewError>(
+ "Unknown CV Record type for a CallerSym object!");
+ }
AutoIndent Indent(P, 7);
for (const auto &I : Caller.Indices) {
- P.formatLine("callee: {0}", idIndex(I));
+ P.formatLine(Format, idIndex(I));
}
return Error::success();
}
@@ -905,3 +937,17 @@
Annot.Strings));
return Error::success();
}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ JumpTableSym &JumpTable) {
+ AutoIndent Indent(P, 7);
+ P.formatLine(
+ "base = {0}, switchtype = {1}, branch = {2}, table = {3}, entriescount = "
+ "{4}",
+ formatSegmentOffset(JumpTable.BaseSegment, JumpTable.BaseOffset),
+ formatJumpTableEntrySize(JumpTable.SwitchType),
+ formatSegmentOffset(JumpTable.BranchSegment, JumpTable.BranchOffset),
+ formatSegmentOffset(JumpTable.TableSegment, JumpTable.TableOffset),
+ JumpTable.EntriesCount);
+ return Error::success();
+}
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
index f43c5c1..50c8f5d 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
@@ -15,9 +15,7 @@
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
-#include <list>
#include <memory>
-#include <unordered_map>
namespace llvm {
class BitVector;
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
index 8f78b3b..f7ef3c6 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
@@ -9,8 +9,6 @@
#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
-#include "llvm/ADT/BitVector.h"
-
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
namespace llvm {
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.cpp
index 878fb77..b392582 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.cpp
@@ -9,7 +9,6 @@
#include "StreamUtil.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
index 5ae720a..c7653b7 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
@@ -55,7 +55,7 @@
// - globals
// - modi symbols
// - LF_UDT_MOD_SRC_LINE? VC always links these in.
- for (SymbolGroup SG : File.symbol_groups()) {
+ for (const SymbolGroup &SG : File.symbol_groups()) {
if (File.isObj()) {
for (const auto &SS : SG.getDebugSubsections()) {
// FIXME: Are there other type-referencing subsections? Inlinees?
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
index 61cad15..9da14cc 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -27,8 +27,6 @@
#include "YAMLOutputStyle.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Magic.h"
@@ -842,7 +840,7 @@
ExitOnErr(DbiBuilder.addModuleSourceFile(ModiBuilder, S));
if (MI.Modi) {
const auto &ModiStream = *MI.Modi;
- for (auto Symbol : ModiStream.Symbols) {
+ for (const auto &Symbol : ModiStream.Symbols) {
ModiBuilder.addSymbol(
Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb));
}
@@ -1415,7 +1413,7 @@
SourceStream = File.createIndexedStream(Index);
auto OutFile = ExitOnErr(
FileOutputBuffer::create(OutFileName, SourceStream->getLength()));
- FileBufferByteStream DestStream(std::move(OutFile), llvm::support::little);
+ FileBufferByteStream DestStream(std::move(OutFile), llvm::endianness::little);
BinaryStreamWriter Writer(DestStream);
ExitOnErr(Writer.writeStreamRef(*SourceStream));
ExitOnErr(DestStream.commit());
@@ -1576,7 +1574,7 @@
if (opts::yaml2pdb::YamlPdbOutputFile.empty()) {
SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue());
sys::path::replace_extension(OutputFilename, ".pdb");
- opts::yaml2pdb::YamlPdbOutputFile = std::string(OutputFilename.str());
+ opts::yaml2pdb::YamlPdbOutputFile = std::string(OutputFilename);
}
yamlToPdb(opts::yaml2pdb::InputFilename);
} else if (opts::DiaDumpSubcommand) {
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
index 8766d70..b8c8033 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -9,7 +9,6 @@
#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
#include "llvm/Support/CommandLine.h"
diff --git a/src/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp b/src/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp
index da10ddc..239aa1c 100644
--- a/src/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -30,11 +30,11 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -46,10 +46,36 @@
#include <queue>
using namespace llvm;
+using ProfCorrelatorKind = InstrProfCorrelator::ProfCorrelatorKind;
-// We use this string to indicate that there are
-// multiple static functions map to the same name.
-const std::string DuplicateNameStr = "----";
+// https://llvm.org/docs/CommandGuide/llvm-profdata.html has documentations
+// on each subcommand.
+cl::SubCommand ShowSubcommand(
+ "show",
+ "Takes a profile data file and displays the profiles. See detailed "
+ "documentation in "
+ "https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-show");
+cl::SubCommand OrderSubcommand(
+ "order",
+ "Reads temporal profiling traces from a profile and outputs a function "
+ "order that reduces the number of page faults for those traces. See "
+ "detailed documentation in "
+ "https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-order");
+cl::SubCommand OverlapSubcommand(
+ "overlap",
+ "Computes and displays the overlap between two profiles. See detailed "
+ "documentation in "
+ "https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-overlap");
+cl::SubCommand MergeSubcommand(
+ "merge",
+ "Takes several profiles and merge them together. See detailed "
+ "documentation in "
+ "https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge");
+
+namespace {
+enum ProfileKinds { instr, sample, memory };
+enum FailureMode { warnOnly, failIfAnyAreInvalid, failIfAllAreInvalid };
+} // namespace
enum ProfileFormat {
PF_None = 0,
@@ -62,6 +88,337 @@
enum class ShowFormat { Text, Json, Yaml };
+// Common options.
+cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
+ cl::init("-"), cl::desc("Output file"),
+ cl::sub(ShowSubcommand),
+ cl::sub(OrderSubcommand),
+ cl::sub(OverlapSubcommand),
+ cl::sub(MergeSubcommand));
+// NOTE: cl::alias must not have cl::sub(), since aliased option's cl::sub()
+// will be used. llvm::cl::alias::done() method asserts this condition.
+cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
+ cl::aliasopt(OutputFilename));
+
+// Options common to at least two commands.
+cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::sub(MergeSubcommand),
+ cl::sub(OverlapSubcommand), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile")));
+cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>"),
+ cl::sub(ShowSubcommand),
+ cl::sub(OrderSubcommand));
+cl::opt<unsigned> MaxDbgCorrelationWarnings(
+ "max-debug-info-correlation-warnings",
+ cl::desc("The maximum number of warnings to emit when correlating "
+ "profile from debug info (0 = no limit)"),
+ cl::sub(MergeSubcommand), cl::sub(ShowSubcommand), cl::init(5));
+cl::opt<std::string> ProfiledBinary(
+ "profiled-binary", cl::init(""),
+ cl::desc("Path to binary from which the profile was collected."),
+ cl::sub(ShowSubcommand), cl::sub(MergeSubcommand));
+cl::opt<std::string> DebugInfoFilename(
+ "debug-info", cl::init(""),
+ cl::desc(
+ "For show, read and extract profile metadata from debug info and show "
+ "the functions it found. For merge, use the provided debug info to "
+ "correlate the raw profile."),
+ cl::sub(ShowSubcommand), cl::sub(MergeSubcommand));
+cl::opt<std::string>
+ BinaryFilename("binary-file", cl::init(""),
+ cl::desc("For merge, use the provided unstripped bianry to "
+ "correlate the raw profile."),
+ cl::sub(MergeSubcommand));
+cl::opt<std::string> FuncNameFilter(
+ "function",
+ cl::desc("Only functions matching the filter are shown in the output. For "
+ "overlapping CSSPGO, this takes a function name with calling "
+ "context."),
+ cl::sub(ShowSubcommand), cl::sub(OverlapSubcommand),
+ cl::sub(MergeSubcommand));
+
+// TODO: Consider creating a template class (e.g., MergeOption, ShowOption) to
+// factor out the common cl::sub in cl::opt constructor for subcommand-specific
+// options.
+
+// Options specific to merge subcommand.
+cl::list<std::string> InputFilenames(cl::Positional, cl::sub(MergeSubcommand),
+ cl::desc("<filename...>"));
+cl::list<std::string> WeightedInputFilenames("weighted-input",
+ cl::sub(MergeSubcommand),
+ cl::desc("<weight>,<filename>"));
+cl::opt<ProfileFormat> OutputFormat(
+ cl::desc("Format of output profile"), cl::sub(MergeSubcommand),
+ cl::init(PF_Ext_Binary),
+ cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding"),
+ clEnumValN(PF_Ext_Binary, "extbinary",
+ "Extensible binary encoding "
+ "(default)"),
+ clEnumValN(PF_Text, "text", "Text encoding"),
+ clEnumValN(PF_GCC, "gcc",
+ "GCC encoding (only meaningful for -sample)")));
+cl::opt<std::string>
+ InputFilenamesFile("input-files", cl::init(""), cl::sub(MergeSubcommand),
+ cl::desc("Path to file containing newline-separated "
+ "[<weight>,]<filename> entries"));
+cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"),
+ cl::aliasopt(InputFilenamesFile));
+cl::opt<bool> DumpInputFileList(
+ "dump-input-file-list", cl::init(false), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("Dump the list of input files and their weights, then exit"));
+cl::opt<std::string> RemappingFile("remapping-file", cl::value_desc("file"),
+ cl::sub(MergeSubcommand),
+ cl::desc("Symbol remapping file"));
+cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"),
+ cl::aliasopt(RemappingFile));
+cl::opt<bool>
+ UseMD5("use-md5", cl::init(false), cl::Hidden,
+ cl::desc("Choose to use MD5 to represent string in name table (only "
+ "meaningful for -extbinary)"),
+ cl::sub(MergeSubcommand));
+cl::opt<bool> CompressAllSections(
+ "compress-all-sections", cl::init(false), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("Compress all sections when writing the profile (only "
+ "meaningful for -extbinary)"));
+cl::opt<bool> SampleMergeColdContext(
+ "sample-merge-cold-context", cl::init(false), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc(
+ "Merge context sample profiles whose count is below cold threshold"));
+cl::opt<bool> SampleTrimColdContext(
+ "sample-trim-cold-context", cl::init(false), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc(
+ "Trim context sample profiles whose count is below cold threshold"));
+cl::opt<uint32_t> SampleColdContextFrameDepth(
+ "sample-frame-depth-for-cold-context", cl::init(1),
+ cl::sub(MergeSubcommand),
+ cl::desc("Keep the last K frames while merging cold profile. 1 means the "
+ "context-less base profile"));
+cl::opt<size_t> OutputSizeLimit(
+ "output-size-limit", cl::init(0), cl::Hidden, cl::sub(MergeSubcommand),
+ cl::desc("Trim cold functions until profile size is below specified "
+ "limit in bytes. This uses a heursitic and functions may be "
+ "excessively trimmed"));
+cl::opt<bool> GenPartialProfile(
+ "gen-partial-profile", cl::init(false), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("Generate a partial profile (only meaningful for -extbinary)"));
+cl::opt<std::string> SupplInstrWithSample(
+ "supplement-instr-with-sample", cl::init(""), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("Supplement an instr profile with sample profile, to correct "
+ "the profile unrepresentativeness issue. The sample "
+ "profile is the input of the flag. Output will be in instr "
+ "format (The flag only works with -instr)"));
+cl::opt<float> ZeroCounterThreshold(
+ "zero-counter-threshold", cl::init(0.7), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("For the function which is cold in instr profile but hot in "
+ "sample profile, if the ratio of the number of zero counters "
+ "divided by the total number of counters is above the "
+ "threshold, the profile of the function will be regarded as "
+ "being harmful for performance and will be dropped."));
+cl::opt<unsigned> SupplMinSizeThreshold(
+ "suppl-min-size-threshold", cl::init(10), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("If the size of a function is smaller than the threshold, "
+ "assume it can be inlined by PGO early inliner and it won't "
+ "be adjusted based on sample profile."));
+cl::opt<unsigned> InstrProfColdThreshold(
+ "instr-prof-cold-threshold", cl::init(0), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("User specified cold threshold for instr profile which will "
+ "override the cold threshold got from profile summary. "));
+// WARNING: This reservoir size value is propagated to any input indexed
+// profiles for simplicity. Changing this value between invocations could
+// result in sample bias.
+cl::opt<uint64_t> TemporalProfTraceReservoirSize(
+ "temporal-profile-trace-reservoir-size", cl::init(100),
+ cl::sub(MergeSubcommand),
+ cl::desc("The maximum number of stored temporal profile traces (default: "
+ "100)"));
+cl::opt<uint64_t> TemporalProfMaxTraceLength(
+ "temporal-profile-max-trace-length", cl::init(10000),
+ cl::sub(MergeSubcommand),
+ cl::desc("The maximum length of a single temporal profile trace "
+ "(default: 10000)"));
+cl::opt<std::string> FuncNameNegativeFilter(
+ "no-function", cl::init(""),
+ cl::sub(MergeSubcommand),
+ cl::desc("Exclude functions matching the filter from the output."));
+
+cl::opt<FailureMode>
+ FailMode("failure-mode", cl::init(failIfAnyAreInvalid),
+ cl::desc("Failure mode:"), cl::sub(MergeSubcommand),
+ cl::values(clEnumValN(warnOnly, "warn",
+ "Do not fail and just print warnings."),
+ clEnumValN(failIfAnyAreInvalid, "any",
+ "Fail if any profile is invalid."),
+ clEnumValN(failIfAllAreInvalid, "all",
+ "Fail only if all profiles are invalid.")));
+
+cl::opt<bool> OutputSparse(
+ "sparse", cl::init(false), cl::sub(MergeSubcommand),
+ cl::desc("Generate a sparse profile (only meaningful for -instr)"));
+cl::opt<unsigned> NumThreads(
+ "num-threads", cl::init(0), cl::sub(MergeSubcommand),
+ cl::desc("Number of merge threads to use (default: autodetect)"));
+cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
+ cl::aliasopt(NumThreads));
+
+cl::opt<std::string> ProfileSymbolListFile(
+ "prof-sym-list", cl::init(""), cl::sub(MergeSubcommand),
+ cl::desc("Path to file containing the list of function symbols "
+ "used to populate profile symbol list"));
+
+cl::opt<SampleProfileLayout> ProfileLayout(
+ "convert-sample-profile-layout",
+ cl::desc("Convert the generated profile to a profile with a new layout"),
+ cl::sub(MergeSubcommand), cl::init(SPL_None),
+ cl::values(
+ clEnumValN(SPL_Nest, "nest",
+ "Nested profile, the input should be CS flat profile"),
+ clEnumValN(SPL_Flat, "flat",
+ "Profile with nested inlinee flatten out")));
+
+cl::opt<bool> DropProfileSymbolList(
+ "drop-profile-symbol-list", cl::init(false), cl::Hidden,
+ cl::sub(MergeSubcommand),
+ cl::desc("Drop the profile symbol list when merging AutoFDO profiles "
+ "(only meaningful for -sample)"));
+
+// Options specific to overlap subcommand.
+cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
+ cl::desc("<base profile file>"),
+ cl::sub(OverlapSubcommand));
+cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
+ cl::desc("<test profile file>"),
+ cl::sub(OverlapSubcommand));
+
+cl::opt<unsigned long long> SimilarityCutoff(
+ "similarity-cutoff", cl::init(0),
+ cl::desc("For sample profiles, list function names (with calling context "
+ "for csspgo) for overlapped functions "
+ "with similarities below the cutoff (percentage times 10000)."),
+ cl::sub(OverlapSubcommand));
+
+cl::opt<bool> IsCS(
+ "cs", cl::init(false),
+ cl::desc("For context sensitive PGO counts. Does not work with CSSPGO."),
+ cl::sub(OverlapSubcommand));
+
+cl::opt<unsigned long long> OverlapValueCutoff(
+ "value-cutoff", cl::init(-1),
+ cl::desc(
+ "Function level overlap information for every function (with calling "
+ "context for csspgo) in test "
+ "profile with max count value greater then the parameter value"),
+ cl::sub(OverlapSubcommand));
+
+// Options unique to show subcommand.
+cl::opt<bool> ShowCounts("counts", cl::init(false),
+ cl::desc("Show counter values for shown functions"),
+ cl::sub(ShowSubcommand));
+cl::opt<ShowFormat>
+ SFormat("show-format", cl::init(ShowFormat::Text),
+ cl::desc("Emit output in the selected format if supported"),
+ cl::sub(ShowSubcommand),
+ cl::values(clEnumValN(ShowFormat::Text, "text",
+ "emit normal text output (default)"),
+ clEnumValN(ShowFormat::Json, "json", "emit JSON"),
+ clEnumValN(ShowFormat::Yaml, "yaml", "emit YAML")));
+// TODO: Consider replacing this with `--show-format=text-encoding`.
+cl::opt<bool>
+ TextFormat("text", cl::init(false),
+ cl::desc("Show instr profile data in text dump format"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool>
+ JsonFormat("json",
+ cl::desc("Show sample profile data in the JSON format "
+ "(deprecated, please use --show-format=json)"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowIndirectCallTargets(
+ "ic-targets", cl::init(false),
+ cl::desc("Show indirect call site target values for shown functions"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowMemOPSizes(
+ "memop-sizes", cl::init(false),
+ cl::desc("Show the profiled sizes of the memory intrinsic calls "
+ "for shown functions"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
+ cl::desc("Show detailed profile summary"),
+ cl::sub(ShowSubcommand));
+cl::list<uint32_t> DetailedSummaryCutoffs(
+ cl::CommaSeparated, "detailed-summary-cutoffs",
+ cl::desc(
+ "Cutoff percentages (times 10000) for generating detailed summary"),
+ cl::value_desc("800000,901000,999999"), cl::sub(ShowSubcommand));
+cl::opt<bool>
+ ShowHotFuncList("hot-func-list", cl::init(false),
+ cl::desc("Show profile summary of a list of hot functions"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
+ cl::desc("Details for each and every function"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowCS("showcs", cl::init(false),
+ cl::desc("Show context sensitive counts"),
+ cl::sub(ShowSubcommand));
+cl::opt<ProfileKinds> ShowProfileKind(
+ cl::desc("Profile kind supported by show:"), cl::sub(ShowSubcommand),
+ cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile"),
+ clEnumVal(memory, "MemProf memory access profile")));
+cl::opt<uint32_t> TopNFunctions(
+ "topn", cl::init(0),
+ cl::desc("Show the list of functions with the largest internal counts"),
+ cl::sub(ShowSubcommand));
+cl::opt<uint32_t> ShowValueCutoff(
+ "value-cutoff", cl::init(0),
+ cl::desc("Set the count value cutoff. Functions with the maximum count "
+ "less than this value will not be printed out. (Default is 0)"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> OnlyListBelow(
+ "list-below-cutoff", cl::init(false),
+ cl::desc("Only output names of functions whose max count values are "
+ "below the cutoff value"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowProfileSymbolList(
+ "show-prof-sym-list", cl::init(false),
+ cl::desc("Show profile symbol list if it exists in the profile. "),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowSectionInfoOnly(
+ "show-sec-info-only", cl::init(false),
+ cl::desc("Show the information of each section in the sample profile. "
+ "The flag is only usable when the sample profile is in "
+ "extbinary format"),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowBinaryIds("binary-ids", cl::init(false),
+ cl::desc("Show binary ids in the profile. "),
+ cl::sub(ShowSubcommand));
+cl::opt<bool> ShowTemporalProfTraces(
+ "temporal-profile-traces",
+ cl::desc("Show temporal profile traces in the profile."),
+ cl::sub(ShowSubcommand));
+
+cl::opt<bool>
+ ShowCovered("covered", cl::init(false),
+ cl::desc("Show only the functions that have been executed."),
+ cl::sub(ShowSubcommand));
+
+cl::opt<bool> ShowProfileVersion("profile-version", cl::init(false),
+ cl::desc("Show profile version. "),
+ cl::sub(ShowSubcommand));
+
+// We use this string to indicate that there are
+// multiple static functions map to the same name.
+const std::string DuplicateNameStr = "----";
+
static void warn(Twine Message, std::string Whence = "",
std::string Hint = "") {
WithColor::warning();
@@ -112,11 +469,6 @@
exitWithError(EC.message(), std::string(Whence));
}
-namespace {
-enum ProfileKinds { instr, sample, memory };
-enum FailureMode { failIfAnyAreInvalid, failIfAllAreInvalid };
-}
-
static void warnOrExitGivenError(FailureMode FailMode, std::error_code EC,
StringRef Whence = "") {
if (FailMode == failIfAnyAreInvalid)
@@ -199,6 +551,14 @@
StringRef New = RemappingTable.lookup(Name);
return New.empty() ? Name : New;
}
+
+ FunctionId operator()(FunctionId Name) {
+ // MD5 name cannot be remapped.
+ if (!Name.isStringRef())
+ return Name;
+ StringRef New = RemappingTable.lookup(Name.stringRef());
+ return New.empty() ? Name : FunctionId(New);
+ }
};
}
@@ -306,7 +666,22 @@
}
auto FS = vfs::getRealFileSystem();
- auto ReaderOrErr = InstrProfReader::create(Input.Filename, *FS, Correlator);
+ // TODO: This only saves the first non-fatal error from InstrProfReader, and
+ // then added to WriterContext::Errors. However, this is not extensible, if
+ // we have more non-fatal errors from InstrProfReader in the future. How
+ // should this interact with different -failure-mode?
+ std::optional<std::pair<Error, std::string>> ReaderWarning;
+ auto Warn = [&](Error E) {
+ if (ReaderWarning) {
+ consumeError(std::move(E));
+ return;
+ }
+ // Only show the first time an error occurs in this file.
+ auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
+ ReaderWarning = {make_error<InstrProfError>(ErrCode, Msg), Filename};
+ };
+ auto ReaderOrErr =
+ InstrProfReader::create(Input.Filename, *FS, Correlator, Warn);
if (Error E = ReaderOrErr.takeError()) {
// Skip the empty profiles by returning silently.
auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
@@ -354,14 +729,23 @@
Traces, Reader->getTemporalProfTraceStreamSize());
}
if (Reader->hasError()) {
- if (Error E = Reader->getError())
+ if (Error E = Reader->getError()) {
WC->Errors.emplace_back(std::move(E), Filename);
+ return;
+ }
}
std::vector<llvm::object::BuildID> BinaryIds;
- if (Error E = Reader->readBinaryIds(BinaryIds))
+ if (Error E = Reader->readBinaryIds(BinaryIds)) {
WC->Errors.emplace_back(std::move(E), Filename);
+ return;
+ }
WC->Writer.addBinaryIds(BinaryIds);
+
+ if (ReaderWarning) {
+ WC->Errors.emplace_back(std::move(ReaderWarning->first),
+ ReaderWarning->second);
+ }
}
/// Merge the \p Src writer context into \p Dst.
@@ -382,6 +766,62 @@
});
}
+static StringRef
+getFuncName(const StringMap<InstrProfWriter::ProfilingData>::value_type &Val) {
+ return Val.first();
+}
+
+static std::string
+getFuncName(const SampleProfileMap::value_type &Val) {
+ return Val.second.getContext().toString();
+}
+
+template <typename T>
+static void filterFunctions(T &ProfileMap) {
+ bool hasFilter = !FuncNameFilter.empty();
+ bool hasNegativeFilter = !FuncNameNegativeFilter.empty();
+ if (!hasFilter && !hasNegativeFilter)
+ return;
+
+ // If filter starts with '?' it is MSVC mangled name, not a regex.
+ llvm::Regex ProbablyMSVCMangledName("[?@$_0-9A-Za-z]+");
+ if (hasFilter && FuncNameFilter[0] == '?' &&
+ ProbablyMSVCMangledName.match(FuncNameFilter))
+ FuncNameFilter = llvm::Regex::escape(FuncNameFilter);
+ if (hasNegativeFilter && FuncNameNegativeFilter[0] == '?' &&
+ ProbablyMSVCMangledName.match(FuncNameNegativeFilter))
+ FuncNameNegativeFilter = llvm::Regex::escape(FuncNameNegativeFilter);
+
+ size_t Count = ProfileMap.size();
+ llvm::Regex Pattern(FuncNameFilter);
+ llvm::Regex NegativePattern(FuncNameNegativeFilter);
+ std::string Error;
+ if (hasFilter && !Pattern.isValid(Error))
+ exitWithError(Error);
+ if (hasNegativeFilter && !NegativePattern.isValid(Error))
+ exitWithError(Error);
+
+ // Handle MD5 profile, so it is still able to match using the original name.
+ std::string MD5Name = std::to_string(llvm::MD5Hash(FuncNameFilter));
+ std::string NegativeMD5Name =
+ std::to_string(llvm::MD5Hash(FuncNameNegativeFilter));
+
+ for (auto I = ProfileMap.begin(); I != ProfileMap.end();) {
+ auto Tmp = I++;
+ const auto &FuncName = getFuncName(*Tmp);
+ // Negative filter has higher precedence than positive filter.
+ if ((hasNegativeFilter &&
+ (NegativePattern.match(FuncName) ||
+ (FunctionSamples::UseMD5 && NegativeMD5Name == FuncName))) ||
+ (hasFilter && !(Pattern.match(FuncName) ||
+ (FunctionSamples::UseMD5 && MD5Name == FuncName))))
+ ProfileMap.erase(Tmp);
+ }
+
+ llvm::dbgs() << Count - ProfileMap.size() << " of " << Count << " functions "
+ << "in the original profile are filtered.\n";
+}
+
static void writeInstrProfile(StringRef OutputFilename,
ProfileFormat OutputFormat,
InstrProfWriter &Writer) {
@@ -403,26 +843,39 @@
}
}
-static void
-mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename,
- SymbolRemapper *Remapper, StringRef OutputFilename,
- ProfileFormat OutputFormat, uint64_t TraceReservoirSize,
- uint64_t MaxTraceLength, bool OutputSparse,
- unsigned NumThreads, FailureMode FailMode,
- const StringRef ProfiledBinary) {
+static void mergeInstrProfile(const WeightedFileVector &Inputs,
+ SymbolRemapper *Remapper,
+ int MaxDbgCorrelationWarnings,
+ const StringRef ProfiledBinary) {
+ const uint64_t TraceReservoirSize = TemporalProfTraceReservoirSize.getValue();
+ const uint64_t MaxTraceLength = TemporalProfMaxTraceLength.getValue();
if (OutputFormat == PF_Compact_Binary)
exitWithError("Compact Binary is deprecated");
if (OutputFormat != PF_Binary && OutputFormat != PF_Ext_Binary &&
OutputFormat != PF_Text)
exitWithError("unknown format is specified");
- std::unique_ptr<InstrProfCorrelator> Correlator;
+ // TODO: Maybe we should support correlation with mixture of different
+ // correlation modes(w/wo debug-info/object correlation).
+ if (!DebugInfoFilename.empty() && !BinaryFilename.empty())
+ exitWithError("Expected only one of -debug-info, -binary-file");
+ std::string CorrelateFilename;
+ ProfCorrelatorKind CorrelateKind = ProfCorrelatorKind::NONE;
if (!DebugInfoFilename.empty()) {
- if (auto Err =
- InstrProfCorrelator::get(DebugInfoFilename).moveInto(Correlator))
- exitWithError(std::move(Err), DebugInfoFilename);
- if (auto Err = Correlator->correlateProfileData())
- exitWithError(std::move(Err), DebugInfoFilename);
+ CorrelateFilename = DebugInfoFilename;
+ CorrelateKind = ProfCorrelatorKind::DEBUG_INFO;
+ } else if (!BinaryFilename.empty()) {
+ CorrelateFilename = BinaryFilename;
+ CorrelateKind = ProfCorrelatorKind::BINARY;
+ }
+
+ std::unique_ptr<InstrProfCorrelator> Correlator;
+ if (CorrelateKind != InstrProfCorrelator::NONE) {
+ if (auto Err = InstrProfCorrelator::get(CorrelateFilename, CorrelateKind)
+ .moveInto(Correlator))
+ exitWithError(std::move(Err), CorrelateFilename);
+ if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings))
+ exitWithError(std::move(Err), CorrelateFilename);
}
std::mutex ErrorLock;
@@ -484,10 +937,12 @@
warn(toString(std::move(ErrorPair.first)), ErrorPair.second);
}
}
- if (NumErrors == Inputs.size() ||
+ if ((NumErrors == Inputs.size() && FailMode == failIfAllAreInvalid) ||
(NumErrors > 0 && FailMode == failIfAnyAreInvalid))
exitWithError("no profile can be merged");
+ filterFunctions(Contexts[0]->Writer.getProfileData());
+
writeInstrProfile(OutputFilename, OutputFormat, Contexts[0]->Writer);
}
@@ -594,7 +1049,7 @@
auto checkSampleProfileHasFUnique = [&Reader]() {
for (const auto &PD : Reader->getProfiles()) {
- auto &FContext = PD.first;
+ auto &FContext = PD.second.getContext();
if (FContext.toString().find(FunctionSamples::UniqSuffix) !=
std::string::npos) {
return true;
@@ -607,13 +1062,14 @@
auto buildStaticFuncMap = [&StaticFuncMap,
SampleProfileHasFUnique](const StringRef Name) {
- std::string Prefixes[] = {".cpp:", "cc:", ".c:", ".hpp:", ".h:"};
+ std::string FilePrefixes[] = {".cpp", "cc", ".c", ".hpp", ".h"};
size_t PrefixPos = StringRef::npos;
- for (auto &Prefix : Prefixes) {
- PrefixPos = Name.find_insensitive(Prefix);
+ for (auto &FilePrefix : FilePrefixes) {
+ std::string NamePrefix = FilePrefix + kGlobalIdentifierDelimiter;
+ PrefixPos = Name.find_insensitive(NamePrefix);
if (PrefixPos == StringRef::npos)
continue;
- PrefixPos += Prefix.size();
+ PrefixPos += NamePrefix.size();
break;
}
@@ -634,12 +1090,12 @@
// If sample profile and instrumented profile do not agree on symbol
// uniqification.
if (SampleProfileHasFUnique != ProfileHasFUnique) {
- // If instrumented profile uses -funique-internal-linakge-symbols,
+ // If instrumented profile uses -funique-internal-linkage-symbols,
// we need to trim the name.
if (ProfileHasFUnique) {
NewName = NewName.substr(0, PostfixPos);
} else {
- // If sample profile uses -funique-internal-linakge-symbols,
+ // If sample profile uses -funique-internal-linkage-symbols,
// we build the map.
std::string NStr =
NewName.str() + getUniqueInternalLinkagePostfix(FName);
@@ -697,26 +1153,27 @@
//
// InstrProfile has two entries:
// foo
- // bar.cc:bar
+ // bar.cc;bar
//
// After BuildMaxSampleMap, we should have the following in FlattenSampleMap:
// {"foo", {1000, 5000}}
- // {"bar.cc:bar", {11000, 30000}}
+ // {"bar.cc;bar", {11000, 30000}}
//
// foo's has an entry count of 1000, and max body count of 5000.
- // bar.cc:bar has an entry count of 11000 (sum two callsites of 1000 and
+ // bar.cc;bar has an entry count of 11000 (sum two callsites of 1000 and
// 10000), and max count of 30000 (from the callsite in line 8).
//
- // Note that goo's count will remain in bar.cc:bar() as it does not have an
+ // Note that goo's count will remain in bar.cc;bar() as it does not have an
// entry in InstrProfile.
- DenseMap<StringRef, std::pair<uint64_t, uint64_t>> FlattenSampleMap;
+ llvm::StringMap<std::pair<uint64_t, uint64_t>> FlattenSampleMap;
auto BuildMaxSampleMap = [&FlattenSampleMap, &StaticFuncMap,
&InstrProfileMap](const FunctionSamples &FS,
const StringRef &RootName) {
auto BuildMaxSampleMapImpl = [&](const FunctionSamples &FS,
const StringRef &RootName,
auto &BuildImpl) -> void {
- const StringRef &Name = FS.getName();
+ std::string NameStr = FS.getFunction().str();
+ const StringRef Name = NameStr;
const StringRef *NewRootName = &RootName;
uint64_t EntrySample = FS.getHeadSamplesEstimate();
uint64_t MaxBodySample = FS.getMaxCountInside(/* SkipCallSite*/ true);
@@ -770,7 +1227,8 @@
for (auto &PD : Reader->getProfiles()) {
sampleprof::FunctionSamples &FS = PD.second;
- BuildMaxSampleMap(FS, FS.getName());
+ std::string Name = FS.getFunction().str();
+ BuildMaxSampleMap(FS, Name);
}
ProfileSummary InstrPS = *IPBuilder.getSummary();
@@ -806,7 +1264,7 @@
uint64_t SampleMaxCount = std::max(E.second.first, E.second.second);
if (SampleMaxCount < ColdSampleThreshold)
continue;
- const StringRef &Name = E.first;
+ StringRef Name = E.first();
auto It = InstrProfileMap.find(Name);
if (It == InstrProfileMap.end()) {
auto NewName = StaticFuncMap.find(Name);
@@ -840,11 +1298,11 @@
/// should be dropped. \p InstrProfColdThreshold is the user specified
/// cold threshold which will override the cold threshold got from the
/// instr profile summary.
-static void supplementInstrProfile(
- const WeightedFileVector &Inputs, StringRef SampleFilename,
- StringRef OutputFilename, ProfileFormat OutputFormat, bool OutputSparse,
- unsigned SupplMinSizeThreshold, float ZeroCounterThreshold,
- unsigned InstrProfColdThreshold) {
+static void supplementInstrProfile(const WeightedFileVector &Inputs,
+ StringRef SampleFilename, bool OutputSparse,
+ unsigned SupplMinSizeThreshold,
+ float ZeroCounterThreshold,
+ unsigned InstrProfColdThreshold) {
if (OutputFilename.compare("-") == 0)
exitWithError("cannot write indexed profdata format to stdout");
if (Inputs.size() != 1)
@@ -885,7 +1343,7 @@
remapSamples(const sampleprof::FunctionSamples &Samples,
SymbolRemapper &Remapper, sampleprof_error &Error) {
sampleprof::FunctionSamples Result;
- Result.setName(Remapper(Samples.getName()));
+ Result.setFunction(Remapper(Samples.getFunction()));
Result.addTotalSamples(Samples.getTotalSamples());
Result.addHeadSamples(Samples.getHeadSamples());
for (const auto &BodySample : Samples.getBodySamples()) {
@@ -896,7 +1354,7 @@
for (const auto &Target : BodySample.second.getCallTargets()) {
Result.addCalledTargetSamples(BodySample.first.LineOffset,
MaskedDiscriminator,
- Remapper(Target.first()), Target.second);
+ Remapper(Target.first), Target.second);
}
}
for (const auto &CallsiteSamples : Samples.getCallsiteSamples()) {
@@ -905,8 +1363,7 @@
for (const auto &Callsite : CallsiteSamples.second) {
sampleprof::FunctionSamples Remapped =
remapSamples(Callsite.second, Remapper, Error);
- MergeResult(Error,
- Target[std::string(Remapped.getName())].merge(Remapped));
+ MergeResult(Error, Target[Remapped.getFunction()].merge(Remapped));
}
}
return Result;
@@ -978,15 +1435,10 @@
}
}
-static void
-mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
- StringRef OutputFilename, ProfileFormat OutputFormat,
- StringRef ProfileSymbolListFile, bool CompressAllSections,
- bool UseMD5, bool GenPartialProfile,
- SampleProfileLayout ProfileLayout,
- bool SampleMergeColdContext, bool SampleTrimColdContext,
- bool SampleColdContextFrameDepth, FailureMode FailMode,
- bool DropProfileSymbolList, size_t OutputSizeLimit) {
+static void mergeSampleProfile(const WeightedFileVector &Inputs,
+ SymbolRemapper *Remapper,
+ StringRef ProfileSymbolListFile,
+ size_t OutputSizeLimit) {
using namespace sampleprof;
SampleProfileMap ProfileMap;
SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;
@@ -1072,6 +1524,8 @@
ProfileIsCS = FunctionSamples::ProfileIsCS = false;
}
+ filterFunctions(ProfileMap);
+
auto WriterOrErr =
SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
if (std::error_code EC = WriterOrErr.getError())
@@ -1146,7 +1600,7 @@
for (const StringRef &FileWeightEntry : Entries) {
StringRef SanitizedEntry = FileWeightEntry.trim(" \t\v\f\r");
// Skip comments.
- if (SanitizedEntry.startswith("#"))
+ if (SanitizedEntry.starts_with("#"))
continue;
// If there's no comma, it's an unweighted profile.
else if (!SanitizedEntry.contains(','))
@@ -1157,140 +1611,6 @@
}
static int merge_main(int argc, const char *argv[]) {
- cl::list<std::string> InputFilenames(cl::Positional,
- cl::desc("<filename...>"));
- cl::list<std::string> WeightedInputFilenames("weighted-input",
- cl::desc("<weight>,<filename>"));
- cl::opt<std::string> InputFilenamesFile(
- "input-files", cl::init(""),
- cl::desc("Path to file containing newline-separated "
- "[<weight>,]<filename> entries"));
- cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"),
- cl::aliasopt(InputFilenamesFile));
- cl::opt<bool> DumpInputFileList(
- "dump-input-file-list", cl::init(false), cl::Hidden,
- cl::desc("Dump the list of input files and their weights, then exit"));
- cl::opt<std::string> RemappingFile("remapping-file", cl::value_desc("file"),
- cl::desc("Symbol remapping file"));
- cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"),
- cl::aliasopt(RemappingFile));
- cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"), cl::desc("Output file"));
- cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
- cl::aliasopt(OutputFilename));
- cl::opt<ProfileKinds> ProfileKind(
- cl::desc("Profile kind:"), cl::init(instr),
- cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
- clEnumVal(sample, "Sample profile")));
- cl::opt<ProfileFormat> OutputFormat(
- cl::desc("Format of output profile"), cl::init(PF_Ext_Binary),
- cl::values(
- clEnumValN(PF_Binary, "binary", "Binary encoding"),
- clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding "
- "(default)"),
- clEnumValN(PF_Text, "text", "Text encoding"),
- clEnumValN(PF_GCC, "gcc",
- "GCC encoding (only meaningful for -sample)")));
- cl::opt<FailureMode> FailureMode(
- "failure-mode", cl::init(failIfAnyAreInvalid), cl::desc("Failure mode:"),
- cl::values(clEnumValN(failIfAnyAreInvalid, "any",
- "Fail if any profile is invalid."),
- clEnumValN(failIfAllAreInvalid, "all",
- "Fail only if all profiles are invalid.")));
- cl::opt<bool> OutputSparse("sparse", cl::init(false),
- cl::desc("Generate a sparse profile (only meaningful for -instr)"));
- cl::opt<unsigned> NumThreads(
- "num-threads", cl::init(0),
- cl::desc("Number of merge threads to use (default: autodetect)"));
- cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
- cl::aliasopt(NumThreads));
- cl::opt<std::string> ProfileSymbolListFile(
- "prof-sym-list", cl::init(""),
- cl::desc("Path to file containing the list of function symbols "
- "used to populate profile symbol list"));
- cl::opt<bool> CompressAllSections(
- "compress-all-sections", cl::init(false), cl::Hidden,
- cl::desc("Compress all sections when writing the profile (only "
- "meaningful for -extbinary)"));
- cl::opt<bool> UseMD5(
- "use-md5", cl::init(false), cl::Hidden,
- cl::desc("Choose to use MD5 to represent string in name table (only "
- "meaningful for -extbinary)"));
- cl::opt<bool> SampleMergeColdContext(
- "sample-merge-cold-context", cl::init(false), cl::Hidden,
- cl::desc(
- "Merge context sample profiles whose count is below cold threshold"));
- cl::opt<bool> SampleTrimColdContext(
- "sample-trim-cold-context", cl::init(false), cl::Hidden,
- cl::desc(
- "Trim context sample profiles whose count is below cold threshold"));
- cl::opt<uint32_t> SampleColdContextFrameDepth(
- "sample-frame-depth-for-cold-context", cl::init(1),
- cl::desc("Keep the last K frames while merging cold profile. 1 means the "
- "context-less base profile"));
- cl::opt<size_t> OutputSizeLimit(
- "output-size-limit", cl::init(0), cl::Hidden,
- cl::desc("Trim cold functions until profile size is below specified "
- "limit in bytes. This uses a heursitic and functions may be "
- "excessively trimmed"));
- cl::opt<bool> GenPartialProfile(
- "gen-partial-profile", cl::init(false), cl::Hidden,
- cl::desc("Generate a partial profile (only meaningful for -extbinary)"));
- cl::opt<std::string> SupplInstrWithSample(
- "supplement-instr-with-sample", cl::init(""), cl::Hidden,
- cl::desc("Supplement an instr profile with sample profile, to correct "
- "the profile unrepresentativeness issue. The sample "
- "profile is the input of the flag. Output will be in instr "
- "format (The flag only works with -instr)"));
- cl::opt<float> ZeroCounterThreshold(
- "zero-counter-threshold", cl::init(0.7), cl::Hidden,
- cl::desc("For the function which is cold in instr profile but hot in "
- "sample profile, if the ratio of the number of zero counters "
- "divided by the total number of counters is above the "
- "threshold, the profile of the function will be regarded as "
- "being harmful for performance and will be dropped."));
- cl::opt<unsigned> SupplMinSizeThreshold(
- "suppl-min-size-threshold", cl::init(10), cl::Hidden,
- cl::desc("If the size of a function is smaller than the threshold, "
- "assume it can be inlined by PGO early inliner and it won't "
- "be adjusted based on sample profile."));
- cl::opt<unsigned> InstrProfColdThreshold(
- "instr-prof-cold-threshold", cl::init(0), cl::Hidden,
- cl::desc("User specified cold threshold for instr profile which will "
- "override the cold threshold got from profile summary. "));
- cl::opt<SampleProfileLayout> ProfileLayout(
- "convert-sample-profile-layout",
- cl::desc("Convert the generated profile to a profile with a new layout"),
- cl::init(SPL_None),
- cl::values(
- clEnumValN(SPL_Nest, "nest",
- "Nested profile, the input should be CS flat profile"),
- clEnumValN(SPL_Flat, "flat",
- "Profile with nested inlinee flatten out")));
- cl::opt<std::string> DebugInfoFilename(
- "debug-info", cl::init(""),
- cl::desc("Use the provided debug info to correlate the raw profile."));
- cl::opt<std::string> ProfiledBinary(
- "profiled-binary", cl::init(""),
- cl::desc("Path to binary from which the profile was collected."));
- cl::opt<bool> DropProfileSymbolList(
- "drop-profile-symbol-list", cl::init(false), cl::Hidden,
- cl::desc("Drop the profile symbol list when merging AutoFDO profiles "
- "(only meaningful for -sample)"));
- // WARNING: This reservoir size value is propagated to any input indexed
- // profiles for simplicity. Changing this value between invocations could
- // result in sample bias.
- cl::opt<uint64_t> TemporalProfTraceReservoirSize(
- "temporal-profile-trace-reservoir-size", cl::init(100),
- cl::desc("The maximum number of stored temporal profile traces (default: "
- "100)"));
- cl::opt<uint64_t> TemporalProfMaxTraceLength(
- "temporal-profile-max-trace-length", cl::init(10000),
- cl::desc("The maximum length of a single temporal profile trace "
- "(default: 10000)"));
-
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
-
WeightedFileVector WeightedInputs;
for (StringRef Filename : InputFilenames)
addWeightedInput(WeightedInputs, {std::string(Filename), 1});
@@ -1304,7 +1624,7 @@
if (WeightedInputs.empty())
exitWithError("no input files specified. See " +
- sys::path::filename(argv[0]) + " -help");
+ sys::path::filename(argv[0]) + " " + argv[1] + " -help");
if (DumpInputFileList) {
for (auto &WF : WeightedInputs)
@@ -1321,25 +1641,18 @@
exitWithError(
"-supplement-instr-with-sample can only work with -instr. ");
- supplementInstrProfile(WeightedInputs, SupplInstrWithSample, OutputFilename,
- OutputFormat, OutputSparse, SupplMinSizeThreshold,
- ZeroCounterThreshold, InstrProfColdThreshold);
+ supplementInstrProfile(WeightedInputs, SupplInstrWithSample, OutputSparse,
+ SupplMinSizeThreshold, ZeroCounterThreshold,
+ InstrProfColdThreshold);
return 0;
}
if (ProfileKind == instr)
- mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(),
- OutputFilename, OutputFormat,
- TemporalProfTraceReservoirSize,
- TemporalProfMaxTraceLength, OutputSparse, NumThreads,
- FailureMode, ProfiledBinary);
+ mergeInstrProfile(WeightedInputs, Remapper.get(), MaxDbgCorrelationWarnings,
+ ProfiledBinary);
else
- mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename,
- OutputFormat, ProfileSymbolListFile, CompressAllSections,
- UseMD5, GenPartialProfile, ProfileLayout,
- SampleMergeColdContext, SampleTrimColdContext,
- SampleColdContextFrameDepth, FailureMode,
- DropProfileSymbolList, OutputSizeLimit);
+ mergeSampleProfile(WeightedInputs, Remapper.get(), ProfileSymbolListFile,
+ OutputSizeLimit);
return 0;
}
@@ -1375,44 +1688,40 @@
SampleContext BaseName;
SampleContext TestName;
// Number of overlap units
- uint64_t OverlapCount;
+ uint64_t OverlapCount = 0;
// Total samples of overlap units
- uint64_t OverlapSample;
+ uint64_t OverlapSample = 0;
// Number of and total samples of units that only present in base or test
// profile
- uint64_t BaseUniqueCount;
- uint64_t BaseUniqueSample;
- uint64_t TestUniqueCount;
- uint64_t TestUniqueSample;
+ uint64_t BaseUniqueCount = 0;
+ uint64_t BaseUniqueSample = 0;
+ uint64_t TestUniqueCount = 0;
+ uint64_t TestUniqueSample = 0;
// Number of units and total samples in base or test profile
- uint64_t BaseCount;
- uint64_t BaseSample;
- uint64_t TestCount;
- uint64_t TestSample;
+ uint64_t BaseCount = 0;
+ uint64_t BaseSample = 0;
+ uint64_t TestCount = 0;
+ uint64_t TestSample = 0;
// Number of and total samples of units that present in at least one profile
- uint64_t UnionCount;
- uint64_t UnionSample;
+ uint64_t UnionCount = 0;
+ uint64_t UnionSample = 0;
// Weighted similarity
- double Similarity;
+ double Similarity = 0.0;
// For SampleOverlapStats instances representing functions, weights of the
// function in base and test profiles
- double BaseWeight;
- double TestWeight;
+ double BaseWeight = 0.0;
+ double TestWeight = 0.0;
- SampleOverlapStats()
- : OverlapCount(0), OverlapSample(0), BaseUniqueCount(0),
- BaseUniqueSample(0), TestUniqueCount(0), TestUniqueSample(0),
- BaseCount(0), BaseSample(0), TestCount(0), TestSample(0), UnionCount(0),
- UnionSample(0), Similarity(0.0), BaseWeight(0.0), TestWeight(0.0) {}
+ SampleOverlapStats() = default;
};
} // end anonymous namespace
namespace {
struct FuncSampleStats {
- uint64_t SampleSum;
- uint64_t MaxSample;
- uint64_t HotBlockCount;
- FuncSampleStats() : SampleSum(0), MaxSample(0), HotBlockCount(0) {}
+ uint64_t SampleSum = 0;
+ uint64_t MaxSample = 0;
+ uint64_t HotBlockCount = 0;
+ FuncSampleStats() = default;
FuncSampleStats(uint64_t SampleSum, uint64_t MaxSample,
uint64_t HotBlockCount)
: SampleSum(SampleSum), MaxSample(MaxSample),
@@ -2302,49 +2611,18 @@
}
static int overlap_main(int argc, const char *argv[]) {
- cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
- cl::desc("<base profile file>"));
- cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
- cl::desc("<test profile file>"));
- cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
- cl::desc("Output file"));
- cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
- cl::opt<bool> IsCS(
- "cs", cl::init(false),
- cl::desc("For context sensitive PGO counts. Does not work with CSSPGO."));
- cl::opt<unsigned long long> ValueCutoff(
- "value-cutoff", cl::init(-1),
- cl::desc(
- "Function level overlap information for every function (with calling "
- "context for csspgo) in test "
- "profile with max count value greater then the parameter value"));
- cl::opt<std::string> FuncNameFilter(
- "function",
- cl::desc("Function level overlap information for matching functions. For "
- "CSSPGO this takes a a function name with calling context"));
- cl::opt<unsigned long long> SimilarityCutoff(
- "similarity-cutoff", cl::init(0),
- cl::desc("For sample profiles, list function names (with calling context "
- "for csspgo) for overlapped functions "
- "with similarities below the cutoff (percentage times 10000)."));
- cl::opt<ProfileKinds> ProfileKind(
- cl::desc("Profile kind:"), cl::init(instr),
- cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
- clEnumVal(sample, "Sample profile")));
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
-
std::error_code EC;
- raw_fd_ostream OS(Output.data(), EC, sys::fs::OF_TextWithCRLF);
+ raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
if (EC)
- exitWithErrorCode(EC, Output);
+ exitWithErrorCode(EC, OutputFilename);
if (ProfileKind == instr)
overlapInstrProfile(BaseFilename, TestFilename,
- OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS,
- IsCS);
+ OverlapFuncFilters{OverlapValueCutoff, FuncNameFilter},
+ OS, IsCS);
else
overlapSampleProfile(BaseFilename, TestFilename,
- OverlapFuncFilters{ValueCutoff, FuncNameFilter},
+ OverlapFuncFilters{OverlapValueCutoff, FuncNameFilter},
SimilarityCutoff, OS);
return 0;
@@ -2352,12 +2630,10 @@
namespace {
struct ValueSitesStats {
- ValueSitesStats()
- : TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
- TotalNumValues(0) {}
- uint64_t TotalNumValueSites;
- uint64_t TotalNumValueSitesWithValueProfile;
- uint64_t TotalNumValues;
+ ValueSitesStats() = default;
+ uint64_t TotalNumValueSites = 0;
+ uint64_t TotalNumValueSitesWithValueProfile = 0;
+ uint64_t TotalNumValues = 0;
std::vector<unsigned> ValueSitesHistogram;
};
} // namespace
@@ -2389,7 +2665,7 @@
if (Symtab == nullptr)
OS << format("%4" PRIu64, VD[V].Value);
else
- OS << Symtab->getFuncName(VD[V].Value);
+ OS << Symtab->getFuncOrVarName(VD[V].Value);
OS << ", " << format("%10" PRId64, VD[V].Count) << " ] ("
<< format("%.2f%%", (VD[V].Count * 100.0 / SiteSum)) << ")\n";
}
@@ -2410,14 +2686,7 @@
}
}
-static int showInstrProfile(
- const std::string &Filename, bool ShowCounts, uint32_t TopN,
- bool ShowIndirectCallTargets, bool ShowMemOPSizes, bool ShowDetailedSummary,
- std::vector<uint32_t> DetailedSummaryCutoffs, bool ShowAllFunctions,
- bool ShowCS, uint64_t ValueCutoff, bool OnlyListBelow,
- const std::string &ShowFunction, bool TextFormat, bool ShowBinaryIds,
- bool ShowCovered, bool ShowProfileVersion, bool ShowTemporalProfTraces,
- ShowFormat SFormat, raw_fd_ostream &OS) {
+static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
if (SFormat == ShowFormat::Json)
exitWithError("JSON output is not supported for instr profiles");
if (SFormat == ShowFormat::Yaml)
@@ -2451,7 +2720,7 @@
if (!TextFormat && OnlyListBelow) {
OS << "The list of functions with the maximum counter less than "
- << ValueCutoff << ":\n";
+ << ShowValueCutoff << ":\n";
}
// Add marker so that IR-level instrumentation round-trips properly.
@@ -2465,7 +2734,7 @@
continue;
}
bool Show = ShowAllFunctions ||
- (!ShowFunction.empty() && Func.Name.contains(ShowFunction));
+ (!FuncNameFilter.empty() && Func.Name.contains(FuncNameFilter));
bool doTextFormatDump = (Show && TextFormat);
@@ -2512,7 +2781,7 @@
FuncSum += Func.Counts[I];
}
- if (FuncMax < ValueCutoff) {
+ if (FuncMax < ShowValueCutoff) {
++BelowCutoffFunctions;
if (OnlyListBelow) {
OS << " " << Func.Name << ": (Max = " << FuncMax
@@ -2522,8 +2791,8 @@
} else if (OnlyListBelow)
continue;
- if (TopN) {
- if (HottestFuncs.size() == TopN) {
+ if (TopNFunctions) {
+ if (HottestFuncs.size() == TopNFunctions) {
if (HottestFuncs.top().second < FuncMax) {
HottestFuncs.pop();
HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
@@ -2587,25 +2856,25 @@
if (IsIR)
OS << " entry_first = " << Reader->instrEntryBBEnabled();
OS << "\n";
- if (ShowAllFunctions || !ShowFunction.empty())
+ if (ShowAllFunctions || !FuncNameFilter.empty())
OS << "Functions shown: " << ShownFunctions << "\n";
OS << "Total functions: " << PS->getNumFunctions() << "\n";
- if (ValueCutoff > 0) {
- OS << "Number of functions with maximum count (< " << ValueCutoff
+ if (ShowValueCutoff > 0) {
+ OS << "Number of functions with maximum count (< " << ShowValueCutoff
<< "): " << BelowCutoffFunctions << "\n";
- OS << "Number of functions with maximum count (>= " << ValueCutoff
+ OS << "Number of functions with maximum count (>= " << ShowValueCutoff
<< "): " << PS->getNumFunctions() - BelowCutoffFunctions << "\n";
}
OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n";
OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n";
- if (TopN) {
+ if (TopNFunctions) {
std::vector<std::pair<std::string, uint64_t>> SortedHottestFuncs;
while (!HottestFuncs.empty()) {
SortedHottestFuncs.emplace_back(HottestFuncs.top());
HottestFuncs.pop();
}
- OS << "Top " << TopN
+ OS << "Top " << TopNFunctions
<< " functions with the largest internal block counts: \n";
for (auto &hotfunc : llvm::reverse(SortedHottestFuncs))
OS << " " << hotfunc.first << ", max count = " << hotfunc.second << "\n";
@@ -2643,7 +2912,7 @@
OS << " Temporal Profile Trace " << i << " (weight=" << Traces[i].Weight
<< " count=" << Traces[i].FunctionNameRefs.size() << "):\n";
for (auto &NameRef : Traces[i].FunctionNameRefs)
- OS << " " << Reader->getSymtab().getFuncName(NameRef) << "\n";
+ OS << " " << Reader->getSymtab().getFuncOrVarName(NameRef) << "\n";
}
}
@@ -2663,13 +2932,12 @@
namespace {
struct HotFuncInfo {
std::string FuncName;
- uint64_t TotalCount;
- double TotalCountPercent;
- uint64_t MaxCount;
- uint64_t EntryCount;
+ uint64_t TotalCount = 0;
+ double TotalCountPercent = 0.0f;
+ uint64_t MaxCount = 0;
+ uint64_t EntryCount = 0;
- HotFuncInfo()
- : TotalCount(0), TotalCountPercent(0.0f), MaxCount(0), EntryCount(0) {}
+ HotFuncInfo() = default;
HotFuncInfo(StringRef FN, uint64_t TS, double TSP, uint64_t MS, uint64_t ES)
: FuncName(FN.begin(), FN.end()), TotalCount(TS), TotalCountPercent(TSP),
@@ -2795,13 +3063,7 @@
return 0;
}
-static int showSampleProfile(const std::string &Filename, bool ShowCounts,
- uint32_t TopN, bool ShowAllFunctions,
- bool ShowDetailedSummary,
- const std::string &ShowFunction,
- bool ShowProfileSymbolList,
- bool ShowSectionInfoOnly, bool ShowHotFuncList,
- ShowFormat SFormat, raw_fd_ostream &OS) {
+static int showSampleProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
if (SFormat == ShowFormat::Yaml)
exitWithError("YAML output is not supported for sample profiles");
using namespace sampleprof;
@@ -2821,7 +3083,7 @@
if (std::error_code EC = Reader->read())
exitWithErrorCode(EC, Filename);
- if (ShowAllFunctions || ShowFunction.empty()) {
+ if (ShowAllFunctions || FuncNameFilter.empty()) {
if (SFormat == ShowFormat::Json)
Reader->dumpJson(OS);
else
@@ -2833,7 +3095,8 @@
"be printed");
// TODO: parse context string to support filtering by contexts.
- Reader->dumpFunctionProfile(StringRef(ShowFunction), OS);
+ FunctionSamples *FS = Reader->getSamplesFor(StringRef(FuncNameFilter));
+ Reader->dumpFunctionProfile(FS ? *FS : FunctionSamples(), OS);
}
if (ShowProfileSymbolList) {
@@ -2848,15 +3111,14 @@
PS.printDetailedSummary(OS);
}
- if (ShowHotFuncList || TopN)
- showHotFunctionList(Reader->getProfiles(), Reader->getSummary(), TopN, OS);
+ if (ShowHotFuncList || TopNFunctions)
+ showHotFunctionList(Reader->getProfiles(), Reader->getSummary(),
+ TopNFunctions, OS);
return 0;
}
-static int showMemProfProfile(const std::string &Filename,
- const std::string &ProfiledBinary,
- ShowFormat SFormat, raw_fd_ostream &OS) {
+static int showMemProfProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
if (SFormat == ShowFormat::Json)
exitWithError("JSON output is not supported for MemProf");
auto ReaderOr = llvm::memprof::RawMemProfReader::create(
@@ -2875,21 +3137,21 @@
}
static int showDebugInfoCorrelation(const std::string &Filename,
- bool ShowDetailedSummary,
- bool ShowProfileSymbolList,
ShowFormat SFormat, raw_fd_ostream &OS) {
if (SFormat == ShowFormat::Json)
exitWithError("JSON output is not supported for debug info correlation");
std::unique_ptr<InstrProfCorrelator> Correlator;
- if (auto Err = InstrProfCorrelator::get(Filename).moveInto(Correlator))
+ if (auto Err =
+ InstrProfCorrelator::get(Filename, InstrProfCorrelator::DEBUG_INFO)
+ .moveInto(Correlator))
exitWithError(std::move(Err), Filename);
if (SFormat == ShowFormat::Yaml) {
- if (auto Err = Correlator->dumpYaml(OS))
+ if (auto Err = Correlator->dumpYaml(MaxDbgCorrelationWarnings, OS))
exitWithError(std::move(Err), Filename);
return 0;
}
- if (auto Err = Correlator->correlateProfileData())
+ if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings))
exitWithError(std::move(Err), Filename);
InstrProfSymtab Symtab;
@@ -2910,102 +3172,13 @@
}
static int show_main(int argc, const char *argv[]) {
- cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>"));
-
- cl::opt<bool> ShowCounts("counts", cl::init(false),
- cl::desc("Show counter values for shown functions"));
- cl::opt<ShowFormat> SFormat(
- "show-format", cl::init(ShowFormat::Text),
- cl::desc("Emit output in the selected format if supported"),
- cl::values(clEnumValN(ShowFormat::Text, "text",
- "emit normal text output (default)"),
- clEnumValN(ShowFormat::Json, "json", "emit JSON"),
- clEnumValN(ShowFormat::Yaml, "yaml", "emit YAML")));
- // TODO: Consider replacing this with `--show-format=text-encoding`.
- cl::opt<bool> TextFormat(
- "text", cl::init(false),
- cl::desc("Show instr profile data in text dump format"));
- cl::opt<bool> JsonFormat(
- "json", cl::desc("Show sample profile data in the JSON format "
- "(deprecated, please use --show-format=json)"));
- cl::opt<bool> ShowIndirectCallTargets(
- "ic-targets", cl::init(false),
- cl::desc("Show indirect call site target values for shown functions"));
- cl::opt<bool> ShowMemOPSizes(
- "memop-sizes", cl::init(false),
- cl::desc("Show the profiled sizes of the memory intrinsic calls "
- "for shown functions"));
- cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
- cl::desc("Show detailed profile summary"));
- cl::list<uint32_t> DetailedSummaryCutoffs(
- cl::CommaSeparated, "detailed-summary-cutoffs",
- cl::desc(
- "Cutoff percentages (times 10000) for generating detailed summary"),
- cl::value_desc("800000,901000,999999"));
- cl::opt<bool> ShowHotFuncList(
- "hot-func-list", cl::init(false),
- cl::desc("Show profile summary of a list of hot functions"));
- cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
- cl::desc("Details for every function"));
- cl::opt<bool> ShowCS("showcs", cl::init(false),
- cl::desc("Show context sensitive counts"));
- cl::opt<std::string> ShowFunction("function",
- cl::desc("Details for matching functions"));
-
- cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"), cl::desc("Output file"));
- cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
- cl::aliasopt(OutputFilename));
- cl::opt<ProfileKinds> ProfileKind(
- cl::desc("Profile kind:"), cl::init(instr),
- cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
- clEnumVal(sample, "Sample profile"),
- clEnumVal(memory, "MemProf memory access profile")));
- cl::opt<uint32_t> TopNFunctions(
- "topn", cl::init(0),
- cl::desc("Show the list of functions with the largest internal counts"));
- cl::opt<uint32_t> ValueCutoff(
- "value-cutoff", cl::init(0),
- cl::desc("Set the count value cutoff. Functions with the maximum count "
- "less than this value will not be printed out. (Default is 0)"));
- cl::opt<bool> OnlyListBelow(
- "list-below-cutoff", cl::init(false),
- cl::desc("Only output names of functions whose max count values are "
- "below the cutoff value"));
- cl::opt<bool> ShowProfileSymbolList(
- "show-prof-sym-list", cl::init(false),
- cl::desc("Show profile symbol list if it exists in the profile. "));
- cl::opt<bool> ShowSectionInfoOnly(
- "show-sec-info-only", cl::init(false),
- cl::desc("Show the information of each section in the sample profile. "
- "The flag is only usable when the sample profile is in "
- "extbinary format"));
- cl::opt<bool> ShowBinaryIds("binary-ids", cl::init(false),
- cl::desc("Show binary ids in the profile. "));
- cl::opt<bool> ShowTemporalProfTraces(
- "temporal-profile-traces",
- cl::desc("Show temporal profile traces in the profile."));
- cl::opt<std::string> DebugInfoFilename(
- "debug-info", cl::init(""),
- cl::desc("Read and extract profile metadata from debug info and show "
- "the functions it found."));
- cl::opt<bool> ShowCovered(
- "covered", cl::init(false),
- cl::desc("Show only the functions that have been executed."));
- cl::opt<std::string> ProfiledBinary(
- "profiled-binary", cl::init(""),
- cl::desc("Path to binary from which the profile was collected."));
- cl::opt<bool> ShowProfileVersion("profile-version", cl::init(false),
- cl::desc("Show profile version. "));
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
-
if (Filename.empty() && DebugInfoFilename.empty())
exitWithError(
"the positional argument '<profdata-file>' is required unless '--" +
DebugInfoFilename.ArgStr + "' is provided");
if (Filename == OutputFilename) {
- errs() << sys::path::filename(argv[0])
+ errs() << sys::path::filename(argv[0]) << " " << argv[1]
<< ": Input file name cannot be the same as the output file name!\n";
return 1;
}
@@ -3017,36 +3190,20 @@
if (EC)
exitWithErrorCode(EC, OutputFilename);
- if (ShowAllFunctions && !ShowFunction.empty())
+ if (ShowAllFunctions && !FuncNameFilter.empty())
WithColor::warning() << "-function argument ignored: showing all functions\n";
if (!DebugInfoFilename.empty())
- return showDebugInfoCorrelation(DebugInfoFilename, ShowDetailedSummary,
- ShowProfileSymbolList, SFormat, OS);
+ return showDebugInfoCorrelation(DebugInfoFilename, SFormat, OS);
- if (ProfileKind == instr)
- return showInstrProfile(
- Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets,
- ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs,
- ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction,
- TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion,
- ShowTemporalProfTraces, SFormat, OS);
- if (ProfileKind == sample)
- return showSampleProfile(Filename, ShowCounts, TopNFunctions,
- ShowAllFunctions, ShowDetailedSummary,
- ShowFunction, ShowProfileSymbolList,
- ShowSectionInfoOnly, ShowHotFuncList, SFormat, OS);
- return showMemProfProfile(Filename, ProfiledBinary, SFormat, OS);
+ if (ShowProfileKind == instr)
+ return showInstrProfile(SFormat, OS);
+ if (ShowProfileKind == sample)
+ return showSampleProfile(SFormat, OS);
+ return showMemProfProfile(SFormat, OS);
}
static int order_main(int argc, const char *argv[]) {
- cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>"));
- cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"), cl::desc("Output file"));
- cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
- cl::aliasopt(OutputFilename));
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data order\n");
-
std::error_code EC;
raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
if (EC)
@@ -3067,83 +3224,48 @@
BalancedPartitioning BP(Config);
BP.run(Nodes);
- WithColor::note() << "# Ordered " << Nodes.size() << " functions\n";
+ OS << "# Ordered " << Nodes.size() << " functions\n";
+ OS << "# Warning: Mach-O may prefix symbols with \"_\" depending on the "
+ "linkage and this output does not take that into account. Some "
+ "post-processing may be required before passing to the linker via "
+ "-order_file.\n";
for (auto &N : Nodes) {
- auto FuncName = Reader->getSymtab().getFuncName(N.Id);
- if (FuncName.contains(':')) {
- // GlobalValue::getGlobalIdentifier() prefixes the filename if the symbol
- // is local. This logic will break if there is a colon in the filename,
- // but we cannot use rsplit() because ObjC symbols can have colons.
- auto [Filename, ParsedFuncName] = FuncName.split(':');
- // Emit a comment describing where this symbol came from
+ auto [Filename, ParsedFuncName] =
+ getParsedIRPGOFuncName(Reader->getSymtab().getFuncOrVarName(N.Id));
+ if (!Filename.empty())
OS << "# " << Filename << "\n";
- FuncName = ParsedFuncName;
- }
- OS << FuncName << "\n";
+ OS << ParsedFuncName << "\n";
}
return 0;
}
-typedef int (*llvm_profdata_subcommand)(int, const char *[]);
-
-static std::tuple<StringRef, llvm_profdata_subcommand>
- llvm_profdata_subcommands[] = {
- {"merge", merge_main},
- {"show", show_main},
- {"order", order_main},
- {"overlap", overlap_main},
-};
-
int llvm_profdata_main(int argc, char **argvNonConst,
const llvm::ToolContext &) {
const char **argv = const_cast<const char **>(argvNonConst);
- InitLLVM X(argc, argv);
StringRef ProgName(sys::path::filename(argv[0]));
- if (argc > 1) {
- llvm_profdata_subcommand func = nullptr;
- for (auto [subcmd_name, subcmd_action] : llvm_profdata_subcommands)
- if (subcmd_name == argv[1])
- func = subcmd_action;
-
- if (func) {
- std::string Invocation(ProgName.str() + " " + argv[1]);
- argv[1] = Invocation.c_str();
- return func(argc - 1, argv + 1);
- }
-
- if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 ||
- strcmp(argv[1], "--help") == 0) {
-
- errs() << "OVERVIEW: LLVM profile data tools\n\n"
- << "USAGE: " << ProgName << " <command> [args...]\n"
- << "USAGE: " << ProgName << " <command> -help\n\n"
- << "See each individual command --help for more details.\n"
- << "Available commands: "
- << join(map_range(llvm_profdata_subcommands,
- [](auto const &KV) { return std::get<0>(KV); }),
- ", ")
- << "\n";
- return 0;
- }
-
- if (strcmp(argv[1], "--version") == 0) {
- outs() << ProgName << '\n';
- cl::PrintVersionMessage();
- return 0;
- }
+ if (argc < 2) {
+ errs() << ProgName
+ << ": No subcommand specified! Run llvm-profata --help for usage.\n";
+ return 1;
}
- if (argc < 2)
- errs() << ProgName << ": No command specified!\n";
- else
- errs() << ProgName << ": Unknown command!\n";
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data\n");
- errs() << "USAGE: " << ProgName << " <"
- << join(map_range(llvm_profdata_subcommands,
- [](auto const &KV) { return std::get<0>(KV); }),
- "|")
- << "> [args...]\n";
+ if (ShowSubcommand)
+ return show_main(argc, argv);
+
+ if (OrderSubcommand)
+ return order_main(argc, argv);
+
+ if (OverlapSubcommand)
+ return overlap_main(argc, argv);
+
+ if (MergeSubcommand)
+ return merge_main(argc, argv);
+
+ errs() << ProgName
+ << ": Unknown command. Run llvm-profdata --help for usage.\n";
return 1;
}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.cpp b/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.cpp
index ae0fd6d..87df699 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.cpp
@@ -11,6 +11,7 @@
#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
+#include "llvm/Transforms/IPO/SampleProfile.h"
#include <cstdint>
#include <queue>
@@ -35,13 +36,6 @@
// TODO: the actual threshold to be tuned here because the size here is based
// on machine code not LLVM IR.
namespace llvm {
-extern cl::opt<int> SampleHotCallSiteThreshold;
-extern cl::opt<int> SampleColdCallSiteThreshold;
-extern cl::opt<int> ProfileInlineGrowthLimit;
-extern cl::opt<int> ProfileInlineLimitMin;
-extern cl::opt<int> ProfileInlineLimitMax;
-extern cl::opt<bool> SortProfiledSCC;
-
cl::opt<bool> EnableCSPreInliner(
"csspgo-preinliner", cl::Hidden, cl::init(true),
cl::desc("Run a global pre-inliner to merge context profile based on "
@@ -80,8 +74,8 @@
ProfileInlineLimitMax = 50000;
}
-std::vector<StringRef> CSPreInliner::buildTopDownOrder() {
- std::vector<StringRef> Order;
+std::vector<FunctionId> CSPreInliner::buildTopDownOrder() {
+ std::vector<FunctionId> Order;
// Trim cold edges to get a more stable call graph. This allows for a more
// stable top-down order which in turns helps the stablity of the generated
// profile from run to run.
@@ -134,9 +128,8 @@
uint64_t CallsiteCount = 0;
LineLocation Callsite = CalleeNode->getCallSiteLoc();
if (auto CallTargets = CallerSamples->findCallTargetMapAt(Callsite)) {
- SampleRecord::CallTargetMap &TargetCounts = CallTargets.get();
- auto It = TargetCounts.find(CalleeSamples->getName());
- if (It != TargetCounts.end())
+ auto It = CallTargets->find(CalleeSamples->getFunction());
+ if (It != CallTargets->end())
CallsiteCount = It->second;
}
@@ -186,7 +179,7 @@
(NormalizationUpperBound - NormalizationLowerBound);
if (NormalizedHotness > 1.0)
NormalizedHotness = 1.0;
- // Add 1 to to ensure hot callsites get a non-zero threshold, which could
+ // Add 1 to ensure hot callsites get a non-zero threshold, which could
// happen when SampleColdCallSiteThreshold is 0. This is when we do not
// want any inlining for cold callsites.
SampleThreshold = SampleHotCallSiteThreshold * NormalizedHotness * 100 +
@@ -202,7 +195,7 @@
return (Candidate.SizeCost < SampleThreshold);
}
-void CSPreInliner::processFunction(const StringRef Name) {
+void CSPreInliner::processFunction(const FunctionId Name) {
FunctionSamples *FSamples = ContextTracker.getBaseSamplesFor(Name);
if (!FSamples)
return;
@@ -303,7 +296,7 @@
// It also helps better compress context profile to control profile
// size, as we now only need context profile for functions going to
// be inlined.
- for (StringRef FuncName : buildTopDownOrder()) {
+ for (FunctionId FuncName : buildTopDownOrder()) {
processFunction(FuncName);
}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.h b/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.h
index 4d848aa..8a3f16a 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/CSPreInliner.h
@@ -57,8 +57,7 @@
// Tie breaker using GUID so we have stable/deterministic inlining order
assert(LHS.CalleeSamples && RHS.CalleeSamples &&
"Expect non-null FunctionSamples");
- return LHS.CalleeSamples->getGUID(LHS.CalleeSamples->getName()) <
- RHS.CalleeSamples->getGUID(RHS.CalleeSamples->getName());
+ return LHS.CalleeSamples->getGUID() < RHS.CalleeSamples->getGUID();
}
};
@@ -81,8 +80,8 @@
private:
bool getInlineCandidates(ProfiledCandidateQueue &CQueue,
const FunctionSamples *FCallerContextSamples);
- std::vector<StringRef> buildTopDownOrder();
- void processFunction(StringRef Name);
+ std::vector<FunctionId> buildTopDownOrder();
+ void processFunction(FunctionId Name);
bool shouldInline(ProfiledInlineCandidate &Candidate);
uint32_t getFuncSize(const ContextTrieNode *ContextNode);
bool UseContextCost;
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/CallContext.h b/src/llvm-project/llvm/tools/llvm-profgen/CallContext.h
index 5e55213..574833b 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/CallContext.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/CallContext.h
@@ -12,13 +12,12 @@
#include "llvm/ProfileData/SampleProf.h"
#include <sstream>
#include <string>
-#include <vector>
namespace llvm {
namespace sampleprof {
inline std::string getCallSite(const SampleContextFrame &Callsite) {
- std::string CallsiteStr = Callsite.FuncName.str();
+ std::string CallsiteStr = Callsite.Func.str();
CallsiteStr += ":";
CallsiteStr += Twine(Callsite.Location.LineOffset).str();
if (Callsite.Location.Discriminator > 0) {
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp
index 9f45167..313d404 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -597,7 +597,7 @@
// It's in bottom-up order with each frame in one line.
// Extract stack frames from sample
- while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().startswith(" 0x")) {
+ while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().starts_with(" 0x")) {
StringRef FrameStr = TraceIt.getCurrentLine().ltrim();
uint64_t FrameAddr = 0;
if (FrameStr.getAsInteger(16, FrameAddr)) {
@@ -645,7 +645,7 @@
// Skip other unrelated line, find the next valid LBR line
// Note that even for empty call stack, we should skip the address at the
// bottom, otherwise the following pass may generate a truncated callstack
- while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().startswith(" 0x")) {
+ while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().starts_with(" 0x")) {
TraceIt.advance();
}
// Filter out broken stack sample. We may not have complete frame info
@@ -690,14 +690,14 @@
// Parsing call stack and populate into PerfSample.CallStack
if (!extractCallstack(TraceIt, Sample->CallStack)) {
// Skip the next LBR line matched current call stack
- if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().startswith(" 0x"))
+ if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().starts_with(" 0x"))
TraceIt.advance();
return;
}
warnIfMissingMMap();
- if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().startswith(" 0x")) {
+ if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().starts_with(" 0x")) {
// Parsing LBR stack and populate into PerfSample.LBRStack
if (extractLBRStack(TraceIt, Sample->LBRStack)) {
if (IgnoreStackSamples) {
@@ -846,7 +846,7 @@
std::make_shared<StringBasedCtxKey>();
StringRef Line = TraceIt.getCurrentLine();
// Read context stack for CS profile.
- if (Line.startswith("[")) {
+ if (Line.starts_with("[")) {
ProfileIsCS = true;
auto I = ContextStrSet.insert(Line.str());
SampleContext::createCtxVectorFromStr(*I.first, Key->Context);
@@ -1005,7 +1005,7 @@
Line.trim().split(Records, " ", 2, false);
if (Records.size() < 2)
return false;
- if (Records[1].startswith("0x") && Records[1].contains('/'))
+ if (Records[1].starts_with("0x") && Records[1].contains('/'))
return true;
return false;
}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h
index 14137e8..e9f6193 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h
@@ -15,9 +15,7 @@
#include "llvm/Support/Regex.h"
#include <cstdint>
#include <fstream>
-#include <list>
#include <map>
-#include <vector>
using namespace llvm;
using namespace sampleprof;
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp
index 97bc8d5..c4028e6 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp
@@ -208,7 +208,7 @@
}
for (auto *FuncSamples : HotFuncs) {
- auto *Func = Binary->getBinaryFunction(FuncSamples->getName());
+ auto *Func = Binary->getBinaryFunction(FuncSamples->getFunction());
if (!Func)
continue;
uint64_t FuncSize = Func->getFuncSize();
@@ -449,7 +449,7 @@
bool ProfileGenerator::collectFunctionsFromLLVMProfile(
std::unordered_set<const BinaryFunction *> &ProfiledFunctions) {
for (const auto &FS : ProfileMap) {
- if (auto *Func = Binary->getBinaryFunction(FS.first.getName()))
+ if (auto *Func = Binary->getBinaryFunction(FS.second.getFunction()))
ProfiledFunctions.insert(Func);
}
return true;
@@ -466,14 +466,9 @@
}
FunctionSamples &
-ProfileGenerator::getTopLevelFunctionProfile(StringRef FuncName) {
+ProfileGenerator::getTopLevelFunctionProfile(FunctionId FuncName) {
SampleContext Context(FuncName);
- auto Ret = ProfileMap.emplace(Context, FunctionSamples());
- if (Ret.second) {
- FunctionSamples &FProfile = Ret.first->second;
- FProfile.setContext(Context);
- }
- return Ret.first->second;
+ return ProfileMap.Create(Context);
}
void ProfileGenerator::generateProfile() {
@@ -505,14 +500,14 @@
return;
// Move cold profiles into a tmp container.
- std::vector<SampleContext> ColdProfiles;
+ std::vector<hash_code> ColdProfileHashes;
for (const auto &I : ProfileMap) {
if (I.second.getTotalSamples() < ColdCntThreshold)
- ColdProfiles.emplace_back(I.first);
+ ColdProfileHashes.emplace_back(I.first);
}
// Remove the cold profile from ProfileMap.
- for (const auto &I : ColdProfiles)
+ for (const auto &I : ColdProfileHashes)
ProfileMap.erase(I);
}
@@ -591,7 +586,7 @@
FunctionProfile.addCalledTargetSamples(
FrameVec.back().Location.LineOffset,
FrameVec.back().Location.Discriminator,
- CalleeName, Count);
+ FunctionId(CalleeName), Count);
}
}
}
@@ -600,11 +595,11 @@
const SampleContextFrameVector &FrameVec, uint64_t Count) {
// Get top level profile
FunctionSamples *FunctionProfile =
- &getTopLevelFunctionProfile(FrameVec[0].FuncName);
+ &getTopLevelFunctionProfile(FrameVec[0].Func);
FunctionProfile->addTotalSamples(Count);
if (Binary->usePseudoProbes()) {
const auto *FuncDesc = Binary->getFuncDescForGUID(
- Function::getGUID(FunctionProfile->getName()));
+ FunctionProfile->getFunction().getHashCode());
FunctionProfile->setFunctionHash(FuncDesc->FuncHash);
}
@@ -615,16 +610,16 @@
FunctionSamplesMap &SamplesMap =
FunctionProfile->functionSamplesAt(Callsite);
auto Ret =
- SamplesMap.emplace(FrameVec[I].FuncName.str(), FunctionSamples());
+ SamplesMap.emplace(FrameVec[I].Func, FunctionSamples());
if (Ret.second) {
- SampleContext Context(FrameVec[I].FuncName);
+ SampleContext Context(FrameVec[I].Func);
Ret.first->second.setContext(Context);
}
FunctionProfile = &Ret.first->second;
FunctionProfile->addTotalSamples(Count);
if (Binary->usePseudoProbes()) {
const auto *FuncDesc = Binary->getFuncDescForGUID(
- Function::getGUID(FunctionProfile->getName()));
+ FunctionProfile->getFunction().getHashCode());
FunctionProfile->setFunctionHash(FuncDesc->FuncHash);
}
}
@@ -721,10 +716,11 @@
FunctionProfile.addCalledTargetSamples(
FrameVec.back().Location.LineOffset,
getBaseDiscriminator(FrameVec.back().Location.Discriminator),
- CalleeName, Count);
+ FunctionId(CalleeName), Count);
}
// Add head samples for callee.
- FunctionSamples &CalleeProfile = getTopLevelFunctionProfile(CalleeName);
+ FunctionSamples &CalleeProfile =
+ getTopLevelFunctionProfile(FunctionId(CalleeName));
CalleeProfile.addHeadSamples(Count);
}
}
@@ -742,7 +738,7 @@
if (!FProfile) {
FSamplesList.emplace_back();
FProfile = &FSamplesList.back();
- FProfile->setName(ContextNode->getFuncName());
+ FProfile->setFunction(ContextNode->getFuncName());
ContextNode->setFunctionSamples(FProfile);
}
// Update ContextWasInlined attribute for existing contexts.
@@ -904,7 +900,8 @@
if (LeafLoc) {
CallerNode->getFunctionSamples()->addCalledTargetSamples(
LeafLoc->Location.LineOffset,
- getBaseDiscriminator(LeafLoc->Location.Discriminator), CalleeName,
+ getBaseDiscriminator(LeafLoc->Location.Discriminator),
+ FunctionId(CalleeName),
Count);
// Record head sample for called target(callee)
CalleeCallSite = LeafLoc->Location;
@@ -912,7 +909,8 @@
}
ContextTrieNode *CalleeNode =
- CallerNode->getOrCreateChildContext(CalleeCallSite, CalleeName);
+ CallerNode->getOrCreateChildContext(CalleeCallSite,
+ FunctionId(CalleeName));
FunctionSamples *CalleeProfile = getOrCreateFunctionSamples(CalleeNode);
CalleeProfile->addHeadSamples(Count);
}
@@ -1018,9 +1016,7 @@
// Merge function samples of CS profile to calculate profile density.
sampleprof::SampleProfileMap ContextLessProfiles;
- for (const auto &I : ProfileMap) {
- ContextLessProfiles[I.second.getName()].merge(I.second);
- }
+ ProfileConverter::flattenProfile(ProfileMap, ContextLessProfiles, true);
calculateAndShowDensity(ContextLessProfiles);
if (GenCSNestedProfile) {
@@ -1219,7 +1215,7 @@
continue;
FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(),
CallProbe->getDiscriminator(),
- CalleeName, Count);
+ FunctionId(CalleeName), Count);
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h
index 471792e..88cf2dc 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h
@@ -157,7 +157,7 @@
void generateLineNumBasedProfile();
void generateProbeBasedProfile();
RangeSample preprocessRangeCounter(const RangeSample &RangeCounter);
- FunctionSamples &getTopLevelFunctionProfile(StringRef FuncName);
+ FunctionSamples &getTopLevelFunctionProfile(FunctionId FuncName);
// Helper function to get the leaf frame's FunctionProfile by traversing the
// inline stack and meanwhile it adds the total samples for each frame's
// function profile.
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index 4755f75..b40c5f8 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -77,7 +77,7 @@
ContextTrieNode *CurNode = &RootContext;
bool IsLeaf = true;
for (const auto &Callsite : reverse(Context)) {
- StringRef CallerName = Callsite.FuncName;
+ FunctionId CallerName = Callsite.Func;
LineLocation CallsiteLoc = IsLeaf ? LineLocation(0, 0) : Callsite.Location;
CurNode = CurNode->getOrCreateChildContext(CallsiteLoc, CallerName);
IsLeaf = false;
@@ -145,7 +145,8 @@
StringRef CallerName = ProbeFrame.first;
LineLocation CallsiteLoc(ProbeFrame.second, 0);
SizeContext =
- SizeContext->getOrCreateChildContext(CallsiteLoc, CallerName);
+ SizeContext->getOrCreateChildContext(CallsiteLoc,
+ FunctionId(CallerName));
}
// Add 0 size to make known.
SizeContext->addFunctionSize(0);
@@ -479,12 +480,6 @@
if (ShowDisassembly)
outs() << '<' << SymbolName << ">:\n";
- auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) {
- WithColor::warning() << "Invalid instructions at "
- << format("%8" PRIx64, Start) << " - "
- << format("%8" PRIx64, End) << "\n";
- };
-
uint64_t Address = StartAddress;
// Size of a consecutive invalid instruction range starting from Address -1
// backwards.
@@ -577,7 +572,8 @@
}
if (InvalidInstLength) {
- WarnInvalidInsts(Address - InvalidInstLength, Address - 1);
+ AddrsWithInvalidInstruction.insert(
+ {Address - InvalidInstLength, Address - 1});
InvalidInstLength = 0;
}
} else {
@@ -588,7 +584,8 @@
}
if (InvalidInstLength)
- WarnInvalidInsts(Address - InvalidInstLength, Address - 1);
+ AddrsWithInvalidInstruction.insert(
+ {Address - InvalidInstLength, Address - 1});
if (ShowDisassembly)
outs() << "\n";
@@ -707,6 +704,19 @@
}
}
+ if (!AddrsWithInvalidInstruction.empty()) {
+ if (ShowDetailedWarning) {
+ for (auto &Addr : AddrsWithInvalidInstruction) {
+ WithColor::warning()
+ << "Invalid instructions at " << format("%8" PRIx64, Addr.first)
+ << " - " << format("%8" PRIx64, Addr.second) << "\n";
+ }
+ }
+ WithColor::warning() << "Found " << AddrsWithInvalidInstruction.size()
+ << " invalid instructions\n";
+ AddrsWithInvalidInstruction.clear();
+ }
+
// Dissassemble rodata section to check if FS discriminator symbol exists.
checkUseFSDiscriminator(Obj, AllSymbols);
}
@@ -791,10 +801,12 @@
FRange.StartAddress = StartAddress;
FRange.EndAddress = EndAddress;
} else {
- WithColor::warning()
- << "Duplicated symbol start address at "
- << format("%8" PRIx64, StartAddress) << " "
- << R.first->second.getFuncName() << " and " << Name << "\n";
+ AddrsWithMultipleSymbols.insert(StartAddress);
+ if (ShowDetailedWarning)
+ WithColor::warning()
+ << "Duplicated symbol start address at "
+ << format("%8" PRIx64, StartAddress) << " "
+ << R.first->second.getFuncName() << " and " << Name << "\n";
}
}
}
@@ -810,27 +822,46 @@
loadSymbolsFromDWARFUnit(*CompilationUnit.get());
// Handles DWO sections that can either be in .o, .dwo or .dwp files.
+ uint32_t NumOfDWOMissing = 0;
for (const auto &CompilationUnit : DebugContext->compile_units()) {
DWARFUnit *const DwarfUnit = CompilationUnit.get();
- if (std::optional<uint64_t> DWOId = DwarfUnit->getDWOId()) {
+ if (DwarfUnit->getDWOId()) {
DWARFUnit *DWOCU = DwarfUnit->getNonSkeletonUnitDIE(false).getDwarfUnit();
if (!DWOCU->isDWOUnit()) {
- std::string DWOName = dwarf::toString(
- DwarfUnit->getUnitDIE().find(
- {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
- "");
- WithColor::warning()
- << "DWO debug information for " << DWOName
- << " was not loaded. Please check the .o, .dwo or .dwp path.\n";
+ NumOfDWOMissing++;
+ if (ShowDetailedWarning) {
+ std::string DWOName = dwarf::toString(
+ DwarfUnit->getUnitDIE().find(
+ {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
+ "");
+ WithColor::warning() << "DWO debug information for " << DWOName
+ << " was not loaded.\n";
+ }
continue;
}
loadSymbolsFromDWARFUnit(*DWOCU);
}
}
+ if (NumOfDWOMissing)
+ WithColor::warning()
+ << " DWO debug information was not loaded for " << NumOfDWOMissing
+ << " modules. Please check the .o, .dwo or .dwp path.\n";
if (BinaryFunctions.empty())
WithColor::warning() << "Loading of DWARF info completed, but no binary "
"functions have been retrieved.\n";
+ // Populate the hash binary function map for MD5 function name lookup. This
+ // is done after BinaryFunctions are finalized.
+ for (auto &BinaryFunction : BinaryFunctions) {
+ HashBinaryFunctions[MD5Hash(StringRef(BinaryFunction.first))] =
+ &BinaryFunction.second;
+ }
+
+ if (!AddrsWithMultipleSymbols.empty()) {
+ WithColor::warning() << "Found " << AddrsWithMultipleSymbols.size()
+ << " start addresses with multiple symbols\n";
+ AddrsWithMultipleSymbols.clear();
+ }
}
void ProfiledBinary::populateSymbolListFromDWARF(
@@ -865,7 +896,8 @@
SampleContextFrameVector CallStack;
for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) {
const auto &CallerFrame = InlineStack.getFrame(I);
- if (CallerFrame.FunctionName == "<invalid>")
+ if (CallerFrame.FunctionName.empty() ||
+ (CallerFrame.FunctionName == "<invalid>"))
break;
StringRef FunctionName(CallerFrame.FunctionName);
@@ -882,7 +914,7 @@
LineLocation Line(LineOffset, Discriminator);
auto It = NameStrings.insert(FunctionName.str());
- CallStack.emplace_back(*It.first, Line);
+ CallStack.emplace_back(FunctionId(StringRef(*It.first)), Line);
}
return CallStack;
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h
index a6d78c6..0fd12f5 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -33,7 +33,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Transforms/IPO/SampleContextTracker.h"
-#include <list>
#include <map>
#include <set>
#include <sstream>
@@ -220,12 +219,20 @@
// A map of mapping function name to BinaryFunction info.
std::unordered_map<std::string, BinaryFunction> BinaryFunctions;
+ // Lookup BinaryFunctions using the function name's MD5 hash. Needed if the
+ // profile is using MD5.
+ std::unordered_map<uint64_t, BinaryFunction *> HashBinaryFunctions;
+
// A list of binary functions that have samples.
std::unordered_set<const BinaryFunction *> ProfiledFunctions;
// GUID to Elf symbol start address map
DenseMap<uint64_t, uint64_t> SymbolStartAddrs;
+ // These maps are for temporary use of warning diagnosis.
+ DenseSet<int64_t> AddrsWithMultipleSymbols;
+ DenseSet<std::pair<uint64_t, uint64_t>> AddrsWithInvalidInstruction;
+
// Start address to Elf symbol GUID map
std::unordered_multimap<uint64_t, uint64_t> StartAddrToSymMap;
@@ -476,12 +483,18 @@
void setProfiledFunctions(std::unordered_set<const BinaryFunction *> &Funcs) {
ProfiledFunctions = Funcs;
}
-
- BinaryFunction *getBinaryFunction(StringRef FName) {
- auto I = BinaryFunctions.find(FName.str());
- if (I == BinaryFunctions.end())
+
+ BinaryFunction *getBinaryFunction(FunctionId FName) {
+ if (FName.isStringRef()) {
+ auto I = BinaryFunctions.find(FName.str());
+ if (I == BinaryFunctions.end())
+ return nullptr;
+ return &I->second;
+ }
+ auto I = HashBinaryFunctions.find(FName.getHashCode());
+ if (I == HashBinaryFunctions.end())
return nullptr;
- return &I->second;
+ return I->second;
}
uint32_t getFuncSizeForContext(const ContextTrieNode *ContextNode) {
@@ -519,7 +532,7 @@
void flushSymbolizer() { Symbolizer.reset(); }
- MissingFrameInferrer* getMissingContextInferrer() {
+ MissingFrameInferrer *getMissingContextInferrer() {
return MissingContextInferrer.get();
}
@@ -556,7 +569,7 @@
InlineContextStack.clear();
continue;
}
- InlineContextStack.emplace_back(Callsite.first,
+ InlineContextStack.emplace_back(FunctionId(Callsite.first),
LineLocation(Callsite.second, 0));
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.cpp b/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.cpp
index 62eed50..9738fd4 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.cpp
@@ -471,6 +471,10 @@
return writeResource(Res, &ResourceFileWriter::writeMenuBody);
}
+Error ResourceFileWriter::visitMenuExResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeMenuExBody);
+}
+
Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
const auto *Res = cast<StringTableResource>(Base);
@@ -887,7 +891,7 @@
if (!File)
return File.takeError();
- BinaryStreamReader Reader((*File)->getBuffer(), support::little);
+ BinaryStreamReader Reader((*File)->getBuffer(), llvm::endianness::little);
// Read the file headers.
// - At the beginning, ICONDIR/NEWHEADER header.
@@ -1176,6 +1180,7 @@
Error ResourceFileWriter::writeMenuDefinition(
const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
+ // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-menuitemtemplate
assert(Def);
const MenuDefinition *DefPtr = Def.get();
@@ -1202,6 +1207,34 @@
return writeMenuDefinitionList(PopupPtr->SubItems);
}
+Error ResourceFileWriter::writeMenuExDefinition(
+ const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
+ // https://learn.microsoft.com/en-us/windows/win32/menurc/menuex-template-item
+ assert(Def);
+ const MenuDefinition *DefPtr = Def.get();
+
+ padStream(sizeof(uint32_t));
+ if (auto *MenuItemPtr = dyn_cast<MenuExItem>(DefPtr)) {
+ writeInt<uint32_t>(MenuItemPtr->Type);
+ writeInt<uint32_t>(MenuItemPtr->State);
+ writeInt<uint32_t>(MenuItemPtr->Id);
+ writeInt<uint16_t>(Flags);
+ padStream(sizeof(uint16_t));
+ RETURN_IF_ERROR(writeCString(MenuItemPtr->Name));
+ return Error::success();
+ }
+
+ auto *PopupPtr = cast<PopupExItem>(DefPtr);
+ writeInt<uint32_t>(PopupPtr->Type);
+ writeInt<uint32_t>(PopupPtr->State);
+ writeInt<uint32_t>(PopupPtr->Id);
+ writeInt<uint16_t>(Flags);
+ padStream(sizeof(uint16_t));
+ RETURN_IF_ERROR(writeCString(PopupPtr->Name));
+ writeInt<uint32_t>(PopupPtr->HelpId);
+ return writeMenuExDefinitionList(PopupPtr->SubItems);
+}
+
Error ResourceFileWriter::writeMenuDefinitionList(
const MenuDefinitionList &List) {
for (auto &Def : List.Definitions) {
@@ -1216,6 +1249,20 @@
return Error::success();
}
+Error ResourceFileWriter::writeMenuExDefinitionList(
+ const MenuDefinitionList &List) {
+ for (auto &Def : List.Definitions) {
+ uint16_t Flags = Def->getResFlags();
+ // Last element receives an additional 0x80 flag.
+ const uint16_t LastElementFlag = 0x0080;
+ if (&Def == &List.Definitions.back())
+ Flags |= LastElementFlag;
+
+ RETURN_IF_ERROR(writeMenuExDefinition(Def, Flags));
+ }
+ return Error::success();
+}
+
Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
// At first, MENUHEADER structure. In fact, these are two WORDs equal to 0.
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648018.aspx
@@ -1224,6 +1271,17 @@
return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
}
+Error ResourceFileWriter::writeMenuExBody(const RCResource *Base) {
+ // At first, MENUEX_TEMPLATE_HEADER structure.
+ // Ref:
+ // https://learn.microsoft.com/en-us/windows/win32/menurc/menuex-template-header
+ writeInt<uint16_t>(1);
+ writeInt<uint16_t>(4);
+ writeInt<uint32_t>(0);
+
+ return writeMenuExDefinitionList(cast<MenuExResource>(Base)->Elements);
+}
+
// --- StringTableResource helpers. --- //
class BundleResource : public RCResource {
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h
index 7a92f84..9413a0e 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h
@@ -55,6 +55,7 @@
Error visitHTMLResource(const RCResource *) override;
Error visitIconResource(const RCResource *) override;
Error visitMenuResource(const RCResource *) override;
+ Error visitMenuExResource(const RCResource *) override;
Error visitVersionInfoResource(const RCResource *) override;
Error visitStringTableResource(const RCResource *) override;
Error visitUserDefinedResource(const RCResource *) override;
@@ -150,8 +151,12 @@
// MenuResource
Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &,
uint16_t Flags);
+ Error writeMenuExDefinition(const std::unique_ptr<MenuDefinition> &,
+ uint16_t Flags);
Error writeMenuDefinitionList(const MenuDefinitionList &List);
+ Error writeMenuExDefinitionList(const MenuDefinitionList &List);
Error writeMenuBody(const RCResource *);
+ Error writeMenuExBody(const RCResource *);
// StringTableResource
Error visitStringTableBundle(const RCResource *);
@@ -178,8 +183,8 @@
uint64_t writeObject(const ArrayRef<uint8_t> Data);
template <typename T> uint64_t writeInt(const T &Value) {
- support::detail::packed_endian_specific_integral<T, support::little,
- support::unaligned>
+ support::detail::packed_endian_specific_integral<
+ T, llvm::endianness::little, support::unaligned>
Object(Value);
return writeObject(Object);
}
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptCppFilter.cpp b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptCppFilter.cpp
index 6657aa5..3081dbb 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptCppFilter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptCppFilter.cpp
@@ -67,7 +67,7 @@
// false since the preprocessing directives should be filtered out.
Line.consume_front("line");
- if (!Line.startswith(" "))
+ if (!Line.starts_with(" "))
return false; // Not a line directive (pragma etc).
// #line 123 "path/file.h"
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp
index 0037fec..4f02fa5 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp
@@ -80,6 +80,8 @@
Result = parseIconResource();
else if (TypeToken->equalsLower("MENU"))
Result = parseMenuResource();
+ else if (TypeToken->equalsLower("MENUEX"))
+ Result = parseMenuExResource();
else if (TypeToken->equalsLower("RCDATA"))
Result = parseUserDefinedResource(RkRcData);
else if (TypeToken->equalsLower("VERSIONINFO"))
@@ -236,7 +238,24 @@
Expected<StringRef> RCParser::readFilename() {
if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
return getExpectedError("string");
- return read().value();
+ const RCToken &Token = read();
+ StringRef Str = Token.value();
+ if (Token.kind() != Kind::String)
+ return Str;
+ while (isNextTokenKind(Kind::String)) {
+ const RCToken &NextToken = read();
+ StringRef Next = NextToken.value();
+ bool IsWide = Str.consume_front_insensitive("L");
+ Next.consume_front_insensitive("L");
+ bool StrUnquoted = Str.consume_front("\"") && Str.consume_back("\"");
+ bool NextUnquoted = Next.consume_front("\"") && Next.consume_back("\"");
+ assert(StrUnquoted && NextUnquoted);
+ (void)StrUnquoted;
+ (void)NextUnquoted;
+
+ Str = Saver.save(Twine(IsWide ? "L" : "") + "\"" + Str + Next + "\"");
+ }
+ return Str;
}
Expected<StringRef> RCParser::readIdentifier() {
@@ -497,9 +516,10 @@
// Check if this is a file resource.
switch (look().kind()) {
case Kind::String:
- case Kind::Identifier:
- return std::make_unique<UserDefinedResource>(Type, read().value(),
- MemoryFlags);
+ case Kind::Identifier: {
+ ASSIGN_OR_RETURN(Filename, readFilename());
+ return std::make_unique<UserDefinedResource>(Type, *Filename, MemoryFlags);
+ }
default:
break;
}
@@ -518,7 +538,7 @@
}
return std::make_unique<UserDefinedResource>(Type, std::move(Data),
- MemoryFlags);
+ MemoryFlags);
}
RCParser::ParseType RCParser::parseVersionInfoResource() {
@@ -557,7 +577,8 @@
IntOrString Class;
std::optional<IntWithNotMask> Style;
if (ClassUpper == "CONTROL") {
- // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
+ // CONTROL text, id, class, style, x, y, width, height [, exstyle] [,
+ // helpID]
ASSIGN_OR_RETURN(ClassStr, readString());
RETURN_IF_ERROR(consumeType(Kind::Comma));
Class = *ClassStr;
@@ -589,8 +610,8 @@
HelpID = *Val;
}
- return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
- (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
+ return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1], (*Args)[2],
+ (*Args)[3], Style, ExStyle, HelpID, Class);
}
RCParser::ParseType RCParser::parseBitmapResource() {
@@ -620,7 +641,14 @@
ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
ASSIGN_OR_RETURN(Items, parseMenuItemsList());
return std::make_unique<MenuResource>(std::move(*OptStatements),
- std::move(*Items), MemoryFlags);
+ std::move(*Items), MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseMenuExResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(MenuExResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Items, parseMenuExItemsList());
+ return std::make_unique<MenuExResource>(std::move(*Items), MemoryFlags);
}
Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
@@ -682,6 +710,95 @@
return std::move(List);
}
+Expected<MenuDefinitionList> RCParser::parseMenuExItemsList() {
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ MenuDefinitionList List;
+
+ // Read a set of items. Each item is of one of two kinds:
+ // MENUITEM caption:String [,[id][, [type][, state]]]]
+ // POPUP caption:String [,[id][, [type][, [state][, helpID]]]] { popupBody }
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
+
+ bool IsMenuItem = ItemTypeResult->equals_insensitive("MENUITEM");
+ bool IsPopup = ItemTypeResult->equals_insensitive("POPUP");
+ if (!IsMenuItem && !IsPopup)
+ return getExpectedError("MENUITEM, POPUP, END or '}'", true);
+
+ // Not a separator. Read the caption.
+ ASSIGN_OR_RETURN(CaptionResult, readString());
+
+ // If MENUITEM, expect [,[id][, [type][, state]]]]
+ if (IsMenuItem) {
+ uint32_t MenuId = 0;
+ uint32_t MenuType = 0;
+ uint32_t MenuState = 0;
+
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntId = readInt();
+ if (IntId) {
+ MenuId = *IntId;
+ }
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntType = readInt();
+ if (IntType) {
+ MenuType = *IntType;
+ }
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntState = readInt();
+ if (IntState) {
+ MenuState = *IntState;
+ }
+ }
+ }
+ }
+ List.addDefinition(std::make_unique<MenuExItem>(*CaptionResult, MenuId,
+ MenuType, MenuState));
+ continue;
+ }
+
+ assert(IsPopup);
+
+ uint32_t PopupId = 0;
+ uint32_t PopupType = 0;
+ uint32_t PopupState = 0;
+ uint32_t PopupHelpID = 0;
+
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntId = readInt();
+ if (IntId) {
+ PopupId = *IntId;
+ }
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntType = readInt();
+ if (IntType) {
+ PopupType = *IntType;
+ }
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntState = readInt();
+ if (IntState) {
+ PopupState = *IntState;
+ }
+ if (consumeOptionalType(Kind::Comma)) {
+ auto IntHelpID = readInt();
+ if (IntHelpID) {
+ PopupHelpID = *IntHelpID;
+ }
+ }
+ }
+ }
+ }
+ // If POPUP, read submenu items recursively.
+ ASSIGN_OR_RETURN(SubMenuResult, parseMenuExItemsList());
+ List.addDefinition(std::make_unique<PopupExItem>(
+ *CaptionResult, PopupId, PopupType, PopupState, PopupHelpID,
+ std::move(*SubMenuResult)));
+ }
+
+ return std::move(List);
+}
+
RCParser::ParseType RCParser::parseStringTableResource() {
uint16_t MemoryFlags =
parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
@@ -689,7 +806,7 @@
RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
- MemoryFlags);
+ MemoryFlags);
// Read strings until we reach the end of the block.
while (!consumeOptionalType(Kind::BlockEnd)) {
@@ -753,7 +870,7 @@
PrecedingCommas.push_back(HadComma);
}
return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
- std::move(PrecedingCommas));
+ std::move(PrecedingCommas));
}
return getExpectedError("BLOCK or VALUE", true);
@@ -835,7 +952,7 @@
}
}
return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
- FontItalic, FontCharset);
+ FontItalic, FontCharset);
}
RCParser::ParseOptionType RCParser::parseStyleStmt() {
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.h
index a7d3b59..603afd8 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.h
@@ -18,6 +18,7 @@
#include "ResourceScriptToken.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
@@ -143,6 +144,7 @@
ParseType parseIconResource();
ParseType parseHTMLResource();
ParseType parseMenuResource();
+ ParseType parseMenuExResource();
ParseType parseStringTableResource();
ParseType parseUserDefinedResource(IntOrString Type);
ParseType parseVersionInfoResource();
@@ -153,6 +155,9 @@
// Helper MENU parser.
Expected<MenuDefinitionList> parseMenuItemsList();
+ // Helper MENUEX parser.
+ Expected<MenuDefinitionList> parseMenuExItemsList();
+
// Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
// from BEGIN to END.
Expected<std::unique_ptr<VersionInfoBlock>>
@@ -181,6 +186,9 @@
std::vector<RCToken> Tokens;
LocIter CurLoc;
const LocIter End;
+
+ BumpPtrAllocator Alloc;
+ StringSaver Saver{Alloc};
};
} // namespace rc
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.cpp b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
index ef8c345..62df799 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
@@ -102,6 +102,12 @@
return OS << " Menu separator\n";
}
+raw_ostream &MenuExItem::log(raw_ostream &OS) const {
+ OS << " MenuExItem (" << Name << "), ID = " << Id;
+ OS << ", type: " << Type << ", state: " << State;
+ return OS << "\n";
+}
+
raw_ostream &PopupItem::log(raw_ostream &OS) const {
OS << " Popup (" << Name << ")";
logFlags(OS, Flags);
@@ -109,12 +115,25 @@
return SubItems.log(OS);
}
+raw_ostream &PopupExItem::log(raw_ostream &OS) const {
+ OS << " Popup (" << Name << ")";
+ OS << ", type: " << Type << ", state: " << State << ", help ID: " << HelpId;
+ OS << ":\n";
+ return SubItems.log(OS);
+}
+
raw_ostream &MenuResource::log(raw_ostream &OS) const {
OS << "Menu (" << ResName << "):\n";
OptStatements->log(OS);
return Elements.log(OS);
}
+raw_ostream &MenuExResource::log(raw_ostream &OS) const {
+ OS << "MenuEx (" << ResName << "):\n";
+ OptStatements->log(OS);
+ return Elements.log(OS);
+}
+
raw_ostream &StringTableResource::log(raw_ostream &OS) const {
OS << "StringTable:\n";
OptStatements->log(OS);
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h
index 71f6a9d..70e7cec 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h
@@ -17,7 +17,7 @@
#include "ResourceVisitor.h"
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringMap.h"
namespace llvm {
namespace rc {
@@ -536,6 +536,23 @@
}
};
+class MenuExItem : public MenuDefinition {
+public:
+ StringRef Name;
+ uint32_t Id;
+ uint32_t Type;
+ uint32_t State;
+
+ MenuExItem(StringRef Caption, uint32_t ItemId, uint32_t Type, uint32_t State)
+ : Name(Caption), Id(ItemId), Type(Type), State(State) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ MenuDefKind getKind() const override { return MkMenuItem; }
+ static bool classof(const MenuDefinition *D) {
+ return D->getKind() == MkMenuItem;
+ }
+};
+
// POPUP statement definition.
//
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
@@ -550,8 +567,7 @@
: Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
raw_ostream &log(raw_ostream &) const override;
- // This has an additional (0x10) flag. It doesn't match with documented
- // 0x01 flag, though.
+ // This has an additional MF_POPUP (0x10) flag.
uint16_t getResFlags() const override { return Flags | 0x10; }
MenuDefKind getKind() const override { return MkPopup; }
static bool classof(const MenuDefinition *D) {
@@ -559,6 +575,28 @@
}
};
+class PopupExItem : public MenuDefinition {
+public:
+ StringRef Name;
+ uint32_t Id;
+ uint32_t Type;
+ uint32_t State;
+ uint32_t HelpId;
+ MenuDefinitionList SubItems;
+
+ PopupExItem(StringRef Caption, uint32_t Id, uint32_t Type, uint32_t State,
+ uint32_t HelpId, MenuDefinitionList &&SubItemsList)
+ : Name(Caption), Id(Id), Type(Type), State(State), HelpId(HelpId),
+ SubItems(std::move(SubItemsList)) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ uint16_t getResFlags() const override { return 0x01; }
+ MenuDefKind getKind() const override { return MkPopup; }
+ static bool classof(const MenuDefinition *D) {
+ return D->getKind() == MkPopup;
+ }
+};
+
// Menu resource definition.
class MenuResource : public OptStatementsRCResource {
public:
@@ -579,6 +617,25 @@
}
};
+class MenuExResource : public OptStatementsRCResource {
+public:
+ MenuDefinitionList Elements;
+
+ MenuExResource(MenuDefinitionList &&Items, uint16_t Flags)
+ : OptStatementsRCResource({}, Flags), Elements(std::move(Items)) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ IntOrString getResourceType() const override { return RkMenu; }
+ Twine getResourceTypeName() const override { return "MENUEX"; }
+ Error visit(Visitor *V) const override {
+ return V->visitMenuExResource(this);
+ }
+ ResourceKind getKind() const override { return RkMenu; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkMenu;
+ }
+};
+
// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
//
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.cpp b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.cpp
index a8f40ab..aad1060 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.cpp
@@ -274,7 +274,7 @@
}
bool Tokenizer::willNowRead(StringRef FollowingChars) const {
- return Data.drop_front(Pos).startswith(FollowingChars);
+ return Data.drop_front(Pos).starts_with(FollowingChars);
}
bool Tokenizer::canStartIdentifier() const {
@@ -298,12 +298,12 @@
bool Tokenizer::canStartBlockComment() const {
assert(!streamEof());
- return Data.drop_front(Pos).startswith("/*");
+ return Data.drop_front(Pos).starts_with("/*");
}
bool Tokenizer::canStartLineComment() const {
assert(!streamEof());
- return Data.drop_front(Pos).startswith("//");
+ return Data.drop_front(Pos).starts_with("//");
}
bool Tokenizer::canContinueInt() const {
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.h
index cc8ca48..29f7502 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptToken.h
@@ -29,7 +29,6 @@
#include <cstdint>
#include <map>
-#include <string>
#include <vector>
namespace llvm {
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceVisitor.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceVisitor.h
index 843c8d8..a950cd7 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceVisitor.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceVisitor.h
@@ -39,6 +39,7 @@
virtual Error visitHTMLResource(const RCResource *) = 0;
virtual Error visitIconResource(const RCResource *) = 0;
virtual Error visitMenuResource(const RCResource *) = 0;
+ virtual Error visitMenuExResource(const RCResource *) = 0;
virtual Error visitStringTableResource(const RCResource *) = 0;
virtual Error visitUserDefinedResource(const RCResource *) = 0;
virtual Error visitVersionInfoResource(const RCResource *) = 0;
diff --git a/src/llvm-project/llvm/tools/llvm-rc/llvm-rc.cpp b/src/llvm-project/llvm/tools/llvm-rc/llvm-rc.cpp
index 0caa811..1c3379a 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/llvm-rc.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/llvm-rc.cpp
@@ -21,11 +21,11 @@
#include "llvm/Object/WindowsResource.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -43,6 +43,7 @@
using namespace llvm;
using namespace llvm::rc;
+using namespace llvm::opt;
namespace {
@@ -50,9 +51,7 @@
enum ID {
OPT_INVALID = 0, // This is not a correct option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -66,13 +65,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -85,9 +78,7 @@
enum Windres_ID {
WINDRES_INVALID = 0, // This is not a correct option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- WINDRES_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(WINDRES_, __VA_ARGS__),
#include "WindresOpts.inc"
#undef OPTION
};
@@ -101,12 +92,8 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, \
- METAVAR, WINDRES_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, WINDRES_##GROUP, \
- WINDRES_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) \
+ LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(WINDRES_, __VA_ARGS__),
#include "WindresOpts.inc"
#undef OPTION
};
@@ -221,7 +208,7 @@
bool Preprocess = true;
bool PrintCmdAndExit = false;
std::string Triple;
- std::vector<std::string> PreprocessCmd;
+ std::optional<std::string> Preprocessor;
std::vector<std::string> PreprocessArgs;
std::string InputFile;
@@ -241,7 +228,7 @@
void preprocess(StringRef Src, StringRef Dst, const RcOptions &Opts,
const char *Argv0) {
std::string Clang;
- if (Opts.PrintCmdAndExit || !Opts.PreprocessCmd.empty()) {
+ if (Opts.PrintCmdAndExit || Opts.Preprocessor) {
Clang = "clang";
} else {
ErrorOr<std::string> ClangOrErr = findClang(Argv0, Opts.Triple);
@@ -260,16 +247,22 @@
SmallVector<StringRef, 8> Args = {
Clang, "--driver-mode=gcc", "-target", Opts.Triple, "-E",
"-xc", "-DRC_INVOKED"};
- if (!Opts.PreprocessCmd.empty()) {
+ std::string PreprocessorExecutable;
+ if (Opts.Preprocessor) {
Args.clear();
- for (const auto &S : Opts.PreprocessCmd)
- Args.push_back(S);
+ Args.push_back(*Opts.Preprocessor);
+ if (!sys::fs::can_execute(Args[0])) {
+ if (auto P = sys::findProgramByName(Args[0])) {
+ PreprocessorExecutable = *P;
+ Args[0] = PreprocessorExecutable;
+ }
+ }
}
+ for (const auto &S : Opts.PreprocessArgs)
+ Args.push_back(S);
Args.push_back(Src);
Args.push_back("-o");
Args.push_back(Dst);
- for (const auto &S : Opts.PreprocessArgs)
- Args.push_back(S);
if (Opts.PrintCmdAndExit || Opts.BeVerbose) {
for (const auto &A : Args) {
outs() << " ";
@@ -281,9 +274,15 @@
}
// The llvm Support classes don't handle reading from stdout of a child
// process; otherwise we could avoid using a temp file.
- int Res = sys::ExecuteAndWait(Args[0], Args);
+ std::string ErrMsg;
+ int Res =
+ sys::ExecuteAndWait(Args[0], Args, /*Env=*/std::nullopt, /*Redirects=*/{},
+ /*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
if (Res) {
- fatalError("llvm-rc: Preprocessing failed.");
+ if (!ErrMsg.empty())
+ fatalError("llvm-rc: Preprocessing failed: " + ErrMsg);
+ else
+ fatalError("llvm-rc: Preprocessing failed.");
}
}
@@ -341,36 +340,6 @@
return Out;
}
-std::vector<std::string> unescapeSplit(StringRef S) {
- std::vector<std::string> OutArgs;
- std::string Out;
- bool InQuote = false;
- for (int I = 0, E = S.size(); I < E; I++) {
- if (S[I] == '\\') {
- if (I + 1 < E)
- Out.push_back(S[++I]);
- else
- fatalError("Unterminated escape");
- continue;
- }
- if (S[I] == '"') {
- InQuote = !InQuote;
- continue;
- }
- if (S[I] == ' ' && !InQuote) {
- OutArgs.push_back(Out);
- Out.clear();
- continue;
- }
- Out.push_back(S[I]);
- }
- if (InQuote)
- fatalError("Unterminated quote");
- if (!Out.empty())
- OutArgs.push_back(Out);
- return OutArgs;
-}
-
RcOptions parseWindresOptions(ArrayRef<const char *> ArgsArr,
ArrayRef<const char *> InputArgsArray,
std::string Prefix) {
@@ -505,11 +474,8 @@
break;
}
}
- // TODO: If --use-temp-file is set, we shouldn't be unescaping
- // the --preprocessor argument either, only splitting it.
if (InputArgs.hasArg(WINDRES_preprocessor))
- Opts.PreprocessCmd =
- unescapeSplit(InputArgs.getLastArgValue(WINDRES_preprocessor));
+ Opts.Preprocessor = InputArgs.getLastArgValue(WINDRES_preprocessor);
Opts.Params.CodePage = CpWin1252; // Different default
if (InputArgs.hasArg(WINDRES_codepage)) {
@@ -595,7 +561,7 @@
SmallString<128> OutputFile(Opts.InputFile);
llvm::sys::fs::make_absolute(OutputFile);
llvm::sys::path::replace_extension(OutputFile, "res");
- OutArgsInfo.push_back(std::string(OutputFile.str()));
+ OutArgsInfo.push_back(std::string(OutputFile));
}
if (!Opts.IsDryRun) {
if (OutArgsInfo.size() != 1)
@@ -764,7 +730,6 @@
} // anonymous namespace
int llvm_rc_main(int Argc, char **Argv, const llvm::ToolContext &) {
- InitLLVM X(Argc, Argv);
ExitOnErr.setBanner("llvm-rc: ");
char **DashDash = std::find_if(Argv + 1, Argv + Argc,
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
index ef77d4b..b77839c 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -171,6 +171,7 @@
{0xff, 0xe8, 1, &Decoder::opcode_trap_frame},
{0xff, 0xe9, 1, &Decoder::opcode_machine_frame},
{0xff, 0xea, 1, &Decoder::opcode_context},
+ {0xff, 0xeb, 1, &Decoder::opcode_ec_context},
{0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call},
{0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr},
};
@@ -969,6 +970,13 @@
return false;
}
+bool Decoder::opcode_ec_context(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ SW.startLine() << format("0x%02x ; EC context\n", OC[Offset]);
+ ++Offset;
+ return false;
+}
+
bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; clear unwound to call\n",
@@ -1468,7 +1476,7 @@
if (!NameOrErr)
return NameOrErr.takeError();
- if (NameOrErr->startswith(".pdata"))
+ if (NameOrErr->starts_with(".pdata"))
dumpProcedureData(COFF, Section);
}
return Error::success();
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
index 0ffebe5..fa5b31d 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -129,6 +129,8 @@
unsigned Length, bool Prologue);
bool opcode_context(const uint8_t *Opcodes, unsigned &Offset, unsigned Length,
bool Prologue);
+ bool opcode_ec_context(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
bool opcode_clear_unwound_to_call(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
bool opcode_pac_sign_lr(const uint8_t *Opcodes, unsigned &Offset,
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp
index 79fef8b..32b1d6a2 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -110,7 +110,7 @@
private:
StringRef getSymbolName(uint32_t Index);
- void printSymbols() override;
+ void printSymbols(bool ExtraSymInfo) override;
void printDynamicSymbols() override;
void printSymbol(const SymbolRef &Sym);
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc,
@@ -854,17 +854,17 @@
reportError(std::move(E), Obj->getFileName());
auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt);
for (uint32_t i = 0; i < CHPE->CodeMapCount; i++) {
- uint32_t Start = CodeMap[i].StartOffset & ~3;
+ uint32_t Start = CodeMap[i].getStart();
W.startLine() << W.hex(Start) << " - "
<< W.hex(Start + CodeMap[i].Length) << " ";
- switch (CodeMap[i].StartOffset & 3) {
- case CHPE_RANGE_ARM64:
+ switch (CodeMap[i].getType()) {
+ case chpe_range_type::Arm64:
W.getOStream() << "ARM64\n";
break;
- case CHPE_RANGE_ARM64EC:
+ case chpe_range_type::Arm64EC:
W.getOStream() << "ARM64EC\n";
break;
- case CHPE_RANGE_AMD64:
+ case chpe_range_type::Amd64:
W.getOStream() << "X64\n";
break;
default:
@@ -1106,7 +1106,7 @@
if (Error E = Reader.readFixedString(Contents, SubSectionSize))
reportError(std::move(E), Obj->getFileName());
- BinaryStreamRef ST(Contents, support::little);
+ BinaryStreamRef ST(Contents, llvm::endianness::little);
switch (DebugSubsectionKind(SubType)) {
case DebugSubsectionKind::FileChecksums:
if (Error E = CVFileChecksumTable.initialize(ST))
@@ -1148,7 +1148,7 @@
reportError(errorCodeToError(object_error::parse_failed),
Obj->getFileName());
- BinaryStreamReader FSReader(Data, support::little);
+ BinaryStreamReader FSReader(Data, llvm::endianness::little);
initializeFileAndStringTables(FSReader);
// TODO: Convert this over to using ModuleSubstreamVisitor.
@@ -1237,7 +1237,7 @@
}
case DebugSubsectionKind::FrameData: {
// First four bytes is a relocation against the function.
- BinaryStreamReader SR(Contents, llvm::support::little);
+ BinaryStreamReader SR(Contents, llvm::endianness::little);
DebugFrameDataSubsectionRef FrameData;
if (Error E = FrameData.initialize(SR))
@@ -1302,7 +1302,8 @@
ListScope S(W, "FunctionLineTable");
W.printString("LinkageName", Name);
- BinaryStreamReader Reader(FunctionLineTables[Name], support::little);
+ BinaryStreamReader Reader(FunctionLineTables[Name],
+ llvm::endianness::little);
DebugLinesSubsectionRef LineInfo;
if (Error E = LineInfo.initialize(Reader))
@@ -1354,7 +1355,7 @@
CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD),
CompilationCPUType, opts::CodeViewSubsectionBytes);
CVSymbolArray Symbols;
- BinaryStreamReader Reader(BinaryData, llvm::support::little);
+ BinaryStreamReader Reader(BinaryData, llvm::endianness::little);
if (Error E = Reader.readArray(Symbols, Reader.getLength())) {
W.flush();
reportError(std::move(E), Obj->getFileName());
@@ -1369,7 +1370,7 @@
}
void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
- BinaryStreamRef Stream(Subsection, llvm::support::little);
+ BinaryStreamRef Stream(Subsection, llvm::endianness::little);
DebugChecksumsSubsectionRef Checksums;
if (Error E = Checksums.initialize(Stream))
reportError(std::move(E), Obj->getFileName());
@@ -1389,7 +1390,7 @@
}
void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
- BinaryStreamReader SR(Subsection, llvm::support::little);
+ BinaryStreamReader SR(Subsection, llvm::endianness::little);
DebugInlineeLinesSubsectionRef Lines;
if (Error E = Lines.initialize(SR))
reportError(std::move(E), Obj->getFileName());
@@ -1449,7 +1450,7 @@
Obj->getFileName());
CVTypeArray Types;
- BinaryStreamReader Reader(Data, llvm::support::little);
+ BinaryStreamReader Reader(Data, llvm::endianness::little);
if (auto EC = Reader.readArray(Types, Reader.getLength())) {
consumeError(std::move(EC));
W.flush();
@@ -1609,7 +1610,7 @@
}
}
-void COFFDumper::printSymbols() {
+void COFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
ListScope Group(W, "Symbols");
for (const SymbolRef &Symbol : Obj->symbols())
@@ -1945,7 +1946,7 @@
ListScope ResourcesD(W, "Resources");
for (const SectionRef &S : Obj->sections()) {
StringRef Name = unwrapOrError(Obj->getFileName(), S.getName());
- if (!Name.startswith(".rsrc"))
+ if (!Name.starts_with(".rsrc"))
continue;
StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents());
@@ -2091,10 +2092,10 @@
if (Obj->isLittleEndian())
prettyPrintStackMap(
- W, StackMapParser<support::little>(StackMapContentsArray));
+ W, StackMapParser<llvm::endianness::little>(StackMapContentsArray));
else
prettyPrintStackMap(
- W, StackMapParser<support::big>(StackMapContentsArray));
+ W, StackMapParser<llvm::endianness::big>(StackMapContentsArray));
}
void COFFDumper::printAddrsig() {
@@ -2125,7 +2126,7 @@
const uint8_t *End = AddrsigContents.bytes_end();
while (Cur != End) {
unsigned Size;
- const char *Err;
+ const char *Err = nullptr;
uint64_t SymIndex = decodeULEB128(Cur, &Size, End, &Err);
if (Err)
reportError(createError(Err), Obj->getFileName());
@@ -2150,7 +2151,7 @@
StringRef CGProfileContents =
unwrapOrError(Obj->getFileName(), CGProfileSection.getContents());
- BinaryStreamReader Reader(CGProfileContents, llvm::support::little);
+ BinaryStreamReader Reader(CGProfileContents, llvm::endianness::little);
ListScope L(W, "CGProfile");
while (!Reader.empty()) {
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/COFFImportDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/COFFImportDumper.cpp
index c9d5e82..0ab2a17 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/COFFImportDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/COFFImportDumper.cpp
@@ -23,7 +23,7 @@
void dumpCOFFImportFile(const COFFImportFile *File, ScopedPrinter &Writer) {
Writer.startLine() << '\n';
Writer.printString("File", File->getFileName());
- Writer.printString("Format", "COFF-import-file");
+ Writer.printString("Format", File->getFileFormatName());
const coff_import_header *H = File->getCOFFImportHeader();
switch (H->getType()) {
@@ -45,8 +45,14 @@
case COFF::IMPORT_NAME_UNDECORATE:
Writer.printString("Name type", "undecorate");
break;
+ case COFF::IMPORT_NAME_EXPORTAS:
+ Writer.printString("Name type", "export as");
+ break;
}
+ if (H->getNameType() != COFF::IMPORT_ORDINAL)
+ Writer.printString("Export name", File->getExportName());
+
for (const object::BasicSymbolRef &Sym : File->symbols()) {
raw_ostream &OS = Writer.startLine();
OS << "Symbol: ";
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
index 365a598..687d97a 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
@@ -113,8 +113,7 @@
if (!Content)
reportError(Content.takeError(), ObjF.getFileName());
- DataExtractor DE(*Content,
- ELFT::TargetEndianness == support::endianness::little,
+ DataExtractor DE(*Content, ELFT::TargetEndianness == llvm::endianness::little,
ELFT::Is64Bits ? 8 : 4);
DictScope D(W, "Header");
@@ -189,7 +188,7 @@
ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);
DWARFDataExtractor DE(DICtx->getDWARFObj(),
DICtx->getDWARFObj().getEHFrameSection(),
- ELFT::TargetEndianness == support::endianness::little,
+ ELFT::TargetEndianness == llvm::endianness::little,
ELFT::Is64Bits ? 8 : 4);
DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true,
/*EHFrameAddress=*/Address);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp
index bc8e041..387124a 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -21,7 +21,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -58,6 +57,7 @@
#include "llvm/Support/RISCVAttributeParser.h"
#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cinttypes>
@@ -298,11 +298,13 @@
llvm::function_ref<void(const Elf_Relr &)> RelrFn);
virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset,
- bool NonVisibilityBitsUsed) const {};
+ bool NonVisibilityBitsUsed,
+ bool ExtraSymInfo) const {};
virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
std::optional<StringRef> StrTable, bool IsDynamic,
- bool NonVisibilityBitsUsed) const = 0;
+ bool NonVisibilityBitsUsed,
+ bool ExtraSymInfo) const = 0;
virtual void printMipsABIFlags() = 0;
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
@@ -361,7 +363,7 @@
}
void printAttributes(unsigned, std::unique_ptr<ELFAttributeParser>,
- support::endianness);
+ llvm::endianness);
void printMipsReginfo();
void printMipsOptions();
@@ -406,7 +408,7 @@
std::string getStaticSymbolName(uint32_t Index) const;
StringRef getDynamicString(uint64_t Value) const;
- void printSymbolsHelper(bool IsDynamic) const;
+ void printSymbolsHelper(bool IsDynamic, bool ExtraSymInfo) const;
std::string getDynamicEntry(uint64_t Type, uint64_t Value) const;
Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R,
@@ -508,7 +510,8 @@
}
template <class ELFT>
-void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
+void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic,
+ bool ExtraSymInfo) const {
std::optional<StringRef> StrTable;
size_t Entries = 0;
Elf_Sym_Range Syms(nullptr, nullptr);
@@ -549,10 +552,10 @@
this->getElfObject().getELFFile().end())
: DataRegion<Elf_Word>(this->getShndxTable(SymtabSec));
- printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed);
+ printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed, ExtraSymInfo);
for (const Elf_Sym &Sym : Syms)
printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic,
- NonVisibilityBitsUsed);
+ NonVisibilityBitsUsed, ExtraSymInfo);
}
template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
@@ -574,14 +577,16 @@
void printGroupSections() override;
void printRelocations() override;
void printSectionHeaders() override;
- void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
+ void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+ bool ExtraSymInfo) override;
void printHashSymbols() override;
void printSectionDetails() override;
void printDependentLibs() override;
void printDynamicTable() override;
void printDynamicRelocations() override;
void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset,
- bool NonVisibilityBitsUsed) const override;
+ bool NonVisibilityBitsUsed,
+ bool ExtraSymInfo) const override;
void printProgramHeaders(bool PrintProgramHeaders,
cl::boolOrDefault PrintSectionMapping) override;
void printVersionSymbolSection(const Elf_Shdr *Sec) override;
@@ -656,12 +661,14 @@
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
std::optional<StringRef> StrTable, bool IsDynamic,
- bool NonVisibilityBitsUsed) const override;
+ bool NonVisibilityBitsUsed,
+ bool ExtraSymInfo) const override;
void printDynamicRelocHeader(unsigned Type, StringRef Name,
const DynRegionInfo &Reg) override;
std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex,
- DataRegion<Elf_Word> ShndxTable) const;
+ DataRegion<Elf_Word> ShndxTable,
+ bool ExtraSymInfo = false) const;
void printProgramHeaders() override;
void printSectionMapping() override;
void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec,
@@ -686,7 +693,8 @@
void printGroupSections() override;
void printRelocations() override;
void printSectionHeaders() override;
- void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
+ void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+ bool ExtraSymInfo) override;
void printDependentLibs() override;
void printDynamicTable() override;
void printDynamicRelocations() override;
@@ -719,7 +727,8 @@
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
std::optional<StringRef> StrTable, bool IsDynamic,
- bool /*NonVisibilityBitsUsed*/) const override;
+ bool /*NonVisibilityBitsUsed*/,
+ bool /*ExtraSymInfo*/) const override;
void printProgramHeaders() override;
void printSectionMapping() override {}
void printStackSizeEntry(uint64_t Size,
@@ -1075,6 +1084,7 @@
{"AROS", "AROS", ELF::ELFOSABI_AROS},
{"FenixOS", "FenixOS", ELF::ELFOSABI_FENIXOS},
{"CloudABI", "CloudABI", ELF::ELFOSABI_CLOUDABI},
+ {"CUDA", "NVIDIA - CUDA", ELF::ELFOSABI_CUDA},
{"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE}
};
@@ -1467,6 +1477,8 @@
LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_MUTABLE);
LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE);
LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_NOBTCFI);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_SYSCALLS);
LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA);
default:
return "";
@@ -1491,7 +1503,7 @@
return Seg.str();
// E.g. "PT_LOAD" -> "LOAD".
- assert(Seg.startswith("PT_"));
+ assert(Seg.starts_with("PT_"));
return Seg.drop_front(3).str();
}
@@ -1548,135 +1560,152 @@
};
const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion3[] = {
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_NONE),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R600),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R630),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RS880),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV670),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV710),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV730),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV770),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CEDAR),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CYPRESS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_JUNIPER),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_REDWOOD),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_SUMO),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_BARTS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAICOS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAYMAN),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_TURKS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX600),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX601),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX602),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX700),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX701),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX702),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX703),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX704),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX705),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX801),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX802),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX803),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX805),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX810),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX900),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX904),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX906),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX908),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX909),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90A),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90C),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX940),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX941),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX942),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1013),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1031),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1032),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1033),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1034),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1035),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1036),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1100),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1101),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1102),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1103),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1150),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1151),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_V3),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_V3)
+ ENUM_ENT(EF_AMDGPU_MACH_NONE, "none"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_R600, "r600"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_R630, "r630"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RS880, "rs880"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV670, "rv670"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV710, "rv710"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV730, "rv730"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV770, "rv770"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CEDAR, "cedar"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CYPRESS, "cypress"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_JUNIPER, "juniper"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_REDWOOD, "redwood"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_SUMO, "sumo"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_BARTS, "barts"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CAICOS, "caicos"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CAYMAN, "cayman"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_TURKS, "turks"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX600, "gfx600"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX601, "gfx601"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX602, "gfx602"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX700, "gfx700"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX701, "gfx701"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX702, "gfx702"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX703, "gfx703"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX704, "gfx704"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX705, "gfx705"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX801, "gfx801"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX802, "gfx802"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX803, "gfx803"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX805, "gfx805"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX810, "gfx810"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX900, "gfx900"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX902, "gfx902"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX904, "gfx904"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX906, "gfx906"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX908, "gfx908"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX909, "gfx909"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX90A, "gfx90a"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX90C, "gfx90c"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX940, "gfx940"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX941, "gfx941"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX942, "gfx942"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1010, "gfx1010"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1011, "gfx1011"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1012, "gfx1012"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1013, "gfx1013"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1030, "gfx1030"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1031, "gfx1031"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1032, "gfx1032"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1033, "gfx1033"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1034, "gfx1034"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1035, "gfx1035"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1036, "gfx1036"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1100, "gfx1100"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1101, "gfx1101"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1102, "gfx1102"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1103, "gfx1103"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1150, "gfx1150"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1151, "gfx1151"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1200, "gfx1200"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1201, "gfx1201"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_XNACK_V3, "xnack"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_SRAMECC_V3, "sramecc"),
};
const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion4[] = {
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_NONE),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R600),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R630),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RS880),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV670),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV710),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV730),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV770),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CEDAR),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CYPRESS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_JUNIPER),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_REDWOOD),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_SUMO),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_BARTS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAICOS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAYMAN),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_TURKS),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX600),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX601),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX602),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX700),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX701),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX702),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX703),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX704),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX705),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX801),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX802),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX803),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX805),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX810),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX900),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX904),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX906),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX908),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX909),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90A),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90C),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX940),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX941),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX942),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1013),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1031),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1032),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1033),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1034),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1035),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1036),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1100),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1101),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1102),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1103),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1150),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1151),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_ANY_V4),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_OFF_V4),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_ON_V4),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_ANY_V4),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_OFF_V4),
- LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_ON_V4)
+ ENUM_ENT(EF_AMDGPU_MACH_NONE, "none"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_R600, "r600"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_R630, "r630"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RS880, "rs880"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV670, "rv670"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV710, "rv710"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV730, "rv730"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_RV770, "rv770"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CEDAR, "cedar"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CYPRESS, "cypress"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_JUNIPER, "juniper"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_REDWOOD, "redwood"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_SUMO, "sumo"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_BARTS, "barts"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CAICOS, "caicos"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_CAYMAN, "cayman"),
+ ENUM_ENT(EF_AMDGPU_MACH_R600_TURKS, "turks"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX600, "gfx600"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX601, "gfx601"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX602, "gfx602"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX700, "gfx700"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX701, "gfx701"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX702, "gfx702"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX703, "gfx703"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX704, "gfx704"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX705, "gfx705"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX801, "gfx801"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX802, "gfx802"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX803, "gfx803"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX805, "gfx805"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX810, "gfx810"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX900, "gfx900"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX902, "gfx902"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX904, "gfx904"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX906, "gfx906"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX908, "gfx908"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX909, "gfx909"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX90A, "gfx90a"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX90C, "gfx90c"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX940, "gfx940"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX941, "gfx941"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX942, "gfx942"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1010, "gfx1010"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1011, "gfx1011"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1012, "gfx1012"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1013, "gfx1013"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1030, "gfx1030"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1031, "gfx1031"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1032, "gfx1032"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1033, "gfx1033"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1034, "gfx1034"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1035, "gfx1035"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1036, "gfx1036"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1100, "gfx1100"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1101, "gfx1101"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1102, "gfx1102"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1103, "gfx1103"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1150, "gfx1150"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1151, "gfx1151"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1200, "gfx1200"),
+ ENUM_ENT(EF_AMDGPU_MACH_AMDGCN_GFX1201, "gfx1201"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_XNACK_ANY_V4, "xnack"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_XNACK_OFF_V4, "xnack-"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_XNACK_ON_V4, "xnack+"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_SRAMECC_ANY_V4, "sramecc"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_SRAMECC_OFF_V4, "sramecc-"),
+ ENUM_ENT(EF_AMDGPU_FEATURE_SRAMECC_ON_V4, "sramecc+"),
+};
+
+const EnumEntry<unsigned> ElfHeaderNVPTXFlags[] = {
+ ENUM_ENT(EF_CUDA_SM20, "sm_20"), ENUM_ENT(EF_CUDA_SM21, "sm_21"),
+ ENUM_ENT(EF_CUDA_SM30, "sm_30"), ENUM_ENT(EF_CUDA_SM32, "sm_32"),
+ ENUM_ENT(EF_CUDA_SM35, "sm_35"), ENUM_ENT(EF_CUDA_SM37, "sm_37"),
+ ENUM_ENT(EF_CUDA_SM50, "sm_50"), ENUM_ENT(EF_CUDA_SM52, "sm_52"),
+ ENUM_ENT(EF_CUDA_SM53, "sm_53"), ENUM_ENT(EF_CUDA_SM60, "sm_60"),
+ ENUM_ENT(EF_CUDA_SM61, "sm_61"), ENUM_ENT(EF_CUDA_SM62, "sm_62"),
+ ENUM_ENT(EF_CUDA_SM70, "sm_70"), ENUM_ENT(EF_CUDA_SM72, "sm_72"),
+ ENUM_ENT(EF_CUDA_SM75, "sm_75"), ENUM_ENT(EF_CUDA_SM80, "sm_80"),
+ ENUM_ENT(EF_CUDA_SM86, "sm_86"), ENUM_ENT(EF_CUDA_SM87, "sm_87"),
+ ENUM_ENT(EF_CUDA_SM89, "sm_89"), ENUM_ENT(EF_CUDA_SM90, "sm_90"),
};
const EnumEntry<unsigned> ElfHeaderRISCVFlags[] = {
@@ -2014,6 +2043,18 @@
uint64_t StringTableSize = 0;
std::optional<DynRegionInfo> DynSymFromTable;
for (const Elf_Dyn &Dyn : dynamic_table()) {
+ if (Obj.getHeader().e_machine == EM_AARCH64) {
+ switch (Dyn.d_tag) {
+ case ELF::DT_AARCH64_AUTH_RELRSZ:
+ DynRelrRegion.Size = Dyn.getVal();
+ DynRelrRegion.SizePrintName = "DT_AARCH64_AUTH_RELRSZ value";
+ continue;
+ case ELF::DT_AARCH64_AUTH_RELRENT:
+ DynRelrRegion.EntSize = Dyn.getVal();
+ DynRelrRegion.EntSizePrintName = "DT_AARCH64_AUTH_RELRENT value";
+ continue;
+ }
+ }
switch (Dyn.d_tag) {
case ELF::DT_HASH:
HashTable = reinterpret_cast<const Elf_Hash *>(
@@ -2077,10 +2118,12 @@
break;
case ELF::DT_RELR:
case ELF::DT_ANDROID_RELR:
+ case ELF::DT_AARCH64_AUTH_RELR:
DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELRSZ:
case ELF::DT_ANDROID_RELRSZ:
+ case ELF::DT_AARCH64_AUTH_RELRSZ:
DynRelrRegion.Size = Dyn.getVal();
DynRelrRegion.SizePrintName = Dyn.d_tag == ELF::DT_RELRSZ
? "DT_RELRSZ value"
@@ -2088,6 +2131,7 @@
break;
case ELF::DT_RELRENT:
case ELF::DT_ANDROID_RELRENT:
+ case ELF::DT_AARCH64_AUTH_RELRENT:
DynRelrRegion.EntSize = Dyn.getVal();
DynRelrRegion.EntSizePrintName = Dyn.d_tag == ELF::DT_RELRENT
? "DT_RELRENT value"
@@ -2454,6 +2498,8 @@
case DT_PREINIT_ARRAYSZ:
case DT_RELRSZ:
case DT_RELRENT:
+ case DT_AARCH64_AUTH_RELRSZ:
+ case DT_AARCH64_AUTH_RELRENT:
case DT_ANDROID_RELSZ:
case DT_ANDROID_RELASZ:
return std::to_string(Value) + " (bytes)";
@@ -2551,7 +2597,7 @@
llvm::sort(Libs);
for (StringRef L : Libs)
- W.startLine() << L << "\n";
+ W.printString(L);
}
template <class ELFT>
@@ -2741,7 +2787,7 @@
return;
std::vector<size_t> ChainLen(NBucket, 0);
- // Go over all buckets and and note chain lengths of each bucket (total
+ // Go over all buckets and note chain lengths of each bucket (total
// unique chain lengths).
for (size_t B = 0; B < NBucket; ++B) {
BitVector Visited(NChain);
@@ -2832,7 +2878,7 @@
if (Obj.isLE())
printAttributes(ELF::SHT_ARM_ATTRIBUTES,
std::make_unique<ARMAttributeParser>(&W),
- support::little);
+ llvm::endianness::little);
else
reportUniqueWarning("attribute printing not implemented for big-endian "
"ARM objects");
@@ -2841,7 +2887,7 @@
if (Obj.isLE())
printAttributes(ELF::SHT_RISCV_ATTRIBUTES,
std::make_unique<RISCVAttributeParser>(&W),
- support::little);
+ llvm::endianness::little);
else
reportUniqueWarning("attribute printing not implemented for big-endian "
"RISC-V objects");
@@ -2849,7 +2895,7 @@
case EM_MSP430:
printAttributes(ELF::SHT_MSP430_ATTRIBUTES,
std::make_unique<MSP430AttributeParser>(&W),
- support::little);
+ llvm::endianness::little);
break;
case EM_MIPS: {
printMipsABIFlags();
@@ -2875,7 +2921,7 @@
template <class ELFT>
void ELFDumper<ELFT>::printAttributes(
unsigned AttrShType, std::unique_ptr<ELFAttributeParser> AttrParser,
- support::endianness Endianness) {
+ llvm::endianness Endianness) {
assert((AttrShType != ELF::SHT_NULL) && AttrParser &&
"Incomplete ELF attribute implementation");
DictScope BA(W, "BuildAttributes");
@@ -3555,7 +3601,18 @@
if (e.e_version == ELF::EV_CURRENT)
OS << " (current)";
OS << "\n";
- Str = enumToString(e.e_ident[ELF::EI_OSABI], ArrayRef(ElfOSABI));
+ auto OSABI = ArrayRef(ElfOSABI);
+ if (e.e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH &&
+ e.e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) {
+ switch (e.e_machine) {
+ case ELF::EM_AMDGPU:
+ OSABI = ArrayRef(AMDGPUElfOSABI);
+ break;
+ default:
+ break;
+ }
+ }
+ Str = enumToString(e.e_ident[ELF::EI_OSABI], OSABI);
printFields(OS, "OS/ABI:", Str);
printFields(OS,
"ABI Version:", std::to_string(e.e_ident[ELF::EI_ABIVERSION]));
@@ -3599,6 +3656,31 @@
else if (e.e_machine == EM_XTENSA)
ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderXtensaFlags),
unsigned(ELF::EF_XTENSA_MACH));
+ else if (e.e_machine == EM_CUDA)
+ ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderNVPTXFlags),
+ unsigned(ELF::EF_CUDA_SM));
+ else if (e.e_machine == EM_AMDGPU) {
+ switch (e.e_ident[ELF::EI_ABIVERSION]) {
+ default:
+ break;
+ case 0:
+ // ELFOSABI_AMDGPU_PAL, ELFOSABI_AMDGPU_MESA3D support *_V3 flags.
+ [[fallthrough]];
+ case ELF::ELFABIVERSION_AMDGPU_HSA_V3:
+ ElfFlags =
+ printFlags(e.e_flags, ArrayRef(ElfHeaderAMDGPUFlagsABIVersion3),
+ unsigned(ELF::EF_AMDGPU_MACH));
+ break;
+ case ELF::ELFABIVERSION_AMDGPU_HSA_V4:
+ case ELF::ELFABIVERSION_AMDGPU_HSA_V5:
+ ElfFlags =
+ printFlags(e.e_flags, ArrayRef(ElfHeaderAMDGPUFlagsABIVersion4),
+ unsigned(ELF::EF_AMDGPU_MACH),
+ unsigned(ELF::EF_AMDGPU_FEATURE_XNACK_V4),
+ unsigned(ELF::EF_AMDGPU_FEATURE_SRAMECC_V4));
+ break;
+ }
+ }
Str = "0x" + utohexstr(e.e_flags);
if (!ElfFlags.empty())
Str = Str + ", " + ElfFlags;
@@ -3786,9 +3868,12 @@
}
template <class ELFT>
-static void printRelocHeaderFields(formatted_raw_ostream &OS, unsigned SType) {
+static void printRelocHeaderFields(formatted_raw_ostream &OS, unsigned SType,
+ const typename ELFT::Ehdr &EHeader) {
bool IsRela = SType == ELF::SHT_RELA || SType == ELF::SHT_ANDROID_RELA;
- bool IsRelr = SType == ELF::SHT_RELR || SType == ELF::SHT_ANDROID_RELR;
+ bool IsRelr =
+ SType == ELF::SHT_RELR || SType == ELF::SHT_ANDROID_RELR ||
+ (EHeader.e_machine == EM_AARCH64 && SType == ELF::SHT_AARCH64_AUTH_RELR);
if (ELFT::Is64Bits)
OS << " ";
else
@@ -3813,15 +3898,18 @@
uint64_t Offset = Reg.Addr - this->Obj.base();
OS << "\n'" << Name.str().c_str() << "' relocation section at offset 0x"
<< utohexstr(Offset, /*LowerCase=*/true) << " contains " << Reg.Size << " bytes:\n";
- printRelocHeaderFields<ELFT>(OS, Type);
+ printRelocHeaderFields<ELFT>(OS, Type, this->Obj.getHeader());
}
template <class ELFT>
-static bool isRelocationSec(const typename ELFT::Shdr &Sec) {
+static bool isRelocationSec(const typename ELFT::Shdr &Sec,
+ const typename ELFT::Ehdr &EHeader) {
return Sec.sh_type == ELF::SHT_REL || Sec.sh_type == ELF::SHT_RELA ||
Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_ANDROID_REL ||
Sec.sh_type == ELF::SHT_ANDROID_RELA ||
- Sec.sh_type == ELF::SHT_ANDROID_RELR;
+ Sec.sh_type == ELF::SHT_ANDROID_RELR ||
+ (EHeader.e_machine == EM_AARCH64 &&
+ Sec.sh_type == ELF::SHT_AARCH64_AUTH_RELR);
}
template <class ELFT> void GNUELFDumper<ELFT>::printRelocations() {
@@ -3837,8 +3925,10 @@
return RelasOrErr->size();
}
- if (!opts::RawRelr && (Sec.sh_type == ELF::SHT_RELR ||
- Sec.sh_type == ELF::SHT_ANDROID_RELR)) {
+ if (!opts::RawRelr &&
+ (Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_ANDROID_RELR ||
+ (this->Obj.getHeader().e_machine == EM_AARCH64 &&
+ Sec.sh_type == ELF::SHT_AARCH64_AUTH_RELR))) {
Expected<Elf_Relr_Range> RelrsOrErr = this->Obj.relrs(Sec);
if (!RelrsOrErr)
return RelrsOrErr.takeError();
@@ -3850,7 +3940,7 @@
bool HasRelocSections = false;
for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) {
- if (!isRelocationSec<ELFT>(Sec))
+ if (!isRelocationSec<ELFT>(Sec, this->Obj.getHeader()))
continue;
HasRelocSections = true;
@@ -3867,7 +3957,7 @@
OS << "\nRelocation section '" << Name << "' at offset 0x"
<< utohexstr(Offset, /*LowerCase=*/true) << " contains " << EntriesNum
<< " entries:\n";
- printRelocHeaderFields<ELFT>(OS, Sec.sh_type);
+ printRelocHeaderFields<ELFT>(OS, Sec.sh_type, this->Obj.getHeader());
this->printRelocationsHelper(Sec);
}
if (!HasRelocSections)
@@ -3998,7 +4088,8 @@
template <class ELFT>
void GNUELFDumper<ELFT>::printSymtabMessage(const Elf_Shdr *Symtab,
size_t Entries,
- bool NonVisibilityBitsUsed) const {
+ bool NonVisibilityBitsUsed,
+ bool ExtraSymInfo) const {
StringRef Name;
if (Symtab)
Name = this->getPrintableSectionName(*Symtab);
@@ -4008,21 +4099,27 @@
OS << "\nSymbol table for image";
OS << " contains " << Entries << " entries:\n";
- if (ELFT::Is64Bits)
+ if (ELFT::Is64Bits) {
OS << " Num: Value Size Type Bind Vis";
- else
+ if (ExtraSymInfo)
+ OS << "+Other";
+ } else {
OS << " Num: Value Size Type Bind Vis";
+ if (ExtraSymInfo)
+ OS << "+Other";
+ }
- if (NonVisibilityBitsUsed)
- OS << " ";
- OS << " Ndx Name\n";
+ OS.PadToColumn((ELFT::Is64Bits ? 56 : 48) + (NonVisibilityBitsUsed ? 13 : 0));
+ if (ExtraSymInfo)
+ OS << "Ndx(SecName) Name [+ Version Info]\n";
+ else
+ OS << "Ndx Name\n";
}
template <class ELFT>
-std::string
-GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
- unsigned SymIndex,
- DataRegion<Elf_Word> ShndxTable) const {
+std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(
+ const Elf_Sym &Symbol, unsigned SymIndex, DataRegion<Elf_Word> ShndxTable,
+ bool ExtraSymInfo) const {
unsigned SectionIndex = Symbol.st_shndx;
switch (SectionIndex) {
case ELF::SHN_UNDEF:
@@ -4041,7 +4138,8 @@
this->reportUniqueWarning(IndexOrErr.takeError());
return "RSV[0xffff]";
}
- return to_string(format_decimal(*IndexOrErr, 3));
+ SectionIndex = *IndexOrErr;
+ break;
}
default:
// Find if:
@@ -4058,17 +4156,31 @@
SectionIndex <= ELF::SHN_HIRESERVE)
return std::string("RSV[0x") +
to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
- // A normal section with an index
- return to_string(format_decimal(SectionIndex, 3));
+ break;
}
+
+ std::string Extra;
+ if (ExtraSymInfo) {
+ auto Sec = this->Obj.getSection(SectionIndex);
+ if (!Sec) {
+ this->reportUniqueWarning(Sec.takeError());
+ } else {
+ auto SecName = this->Obj.getSectionName(**Sec);
+ if (!SecName)
+ this->reportUniqueWarning(SecName.takeError());
+ else
+ Extra = Twine(" (" + *SecName + ")").str();
+ }
+ }
+ return to_string(format_decimal(SectionIndex, 3)) + Extra;
}
template <class ELFT>
void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
std::optional<StringRef> StrTable,
- bool IsDynamic,
- bool NonVisibilityBitsUsed) const {
+ bool IsDynamic, bool NonVisibilityBitsUsed,
+ bool ExtraSymInfo) const {
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias,
31 + Bias, 38 + Bias, 48 + Bias, 51 + Bias};
@@ -4115,8 +4227,10 @@
}
Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0;
- Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable);
+ Fields[6].Str =
+ getSymbolSectionNdx(Symbol, SymIndex, ShndxTable, ExtraSymInfo);
+ Fields[7].Column += ExtraSymInfo ? 10 : 0;
Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable,
StrTable, IsDynamic);
for (const Field &Entry : Fields)
@@ -4162,13 +4276,14 @@
template <class ELFT>
void GNUELFDumper<ELFT>::printSymbols(bool PrintSymbols,
- bool PrintDynamicSymbols) {
+ bool PrintDynamicSymbols,
+ bool ExtraSymInfo) {
if (!PrintSymbols && !PrintDynamicSymbols)
return;
// GNU readelf prints both the .dynsym and .symtab with --symbols.
- this->printSymbolsHelper(true);
+ this->printSymbolsHelper(true, ExtraSymInfo);
if (PrintSymbols)
- this->printSymbolsHelper(false);
+ this->printSymbolsHelper(false, ExtraSymInfo);
}
template <class ELFT>
@@ -4474,43 +4589,6 @@
}
template <class ELFT>
-static bool checkOffsets(const typename ELFT::Phdr &Phdr,
- const typename ELFT::Shdr &Sec) {
- // SHT_NOBITS sections don't need to have an offset inside the segment.
- if (Sec.sh_type == ELF::SHT_NOBITS)
- return true;
-
- if (Sec.sh_offset < Phdr.p_offset)
- return false;
-
- // Only non-empty sections can be at the end of a segment.
- if (Sec.sh_size == 0)
- return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
- return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
-}
-
-// Check that an allocatable section belongs to a virtual address
-// space of a segment.
-template <class ELFT>
-static bool checkVMA(const typename ELFT::Phdr &Phdr,
- const typename ELFT::Shdr &Sec) {
- if (!(Sec.sh_flags & ELF::SHF_ALLOC))
- return true;
-
- if (Sec.sh_addr < Phdr.p_vaddr)
- return false;
-
- bool IsTbss =
- (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
- // .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
- bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
- // Only non-empty sections can be at the end of a segment.
- if (Sec.sh_size == 0 || IsTbssInNonTLS)
- return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
- return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
-}
-
-template <class ELFT>
static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
const typename ELFT::Shdr &Sec) {
if (Phdr.p_type != ELF::PT_DYNAMIC || Phdr.p_memsz == 0 || Sec.sh_size != 0)
@@ -4641,8 +4719,9 @@
// readelf additionally makes sure it does not print zero sized sections
// at end of segments and for PT_DYNAMIC both start and end of section
// .tbss must only be shown in PT_TLS section.
- if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
- checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
+ if (isSectionInSegment<ELFT>(Phdr, Sec) &&
+ checkTLSSections<ELFT>(Phdr, Sec) &&
+ checkPTDynamic<ELFT>(Phdr, Sec)) {
Sections +=
unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
" ";
@@ -5002,7 +5081,7 @@
const uint8_t *End = Data.end();
while (Cur != End) {
unsigned Size;
- const char *Err;
+ const char *Err = nullptr;
Ret.push_back(decodeULEB128(Cur, &Size, End, &Err));
if (Err)
return createError(Err);
@@ -5102,6 +5181,7 @@
if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI");
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC");
+ DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_GCS, "GCS");
} else {
DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT");
DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK");
@@ -5311,6 +5391,31 @@
}
template <class ELFT>
+static bool printAArch64Note(raw_ostream &OS, uint32_t NoteType,
+ ArrayRef<uint8_t> Desc) {
+ if (NoteType != NT_ARM_TYPE_PAUTH_ABI_TAG)
+ return false;
+
+ OS << " AArch64 PAuth ABI tag: ";
+ if (Desc.size() < 16) {
+ OS << format("<corrupted size: expected at least 16, got %d>", Desc.size());
+ return false;
+ }
+
+ uint64_t Platform =
+ support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 0);
+ uint64_t Version =
+ support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 8);
+ OS << format("platform 0x%" PRIx64 ", version 0x%" PRIx64, Platform, Version);
+
+ if (Desc.size() > 16)
+ OS << ", additional info 0x"
+ << toHex(ArrayRef<uint8_t>(Desc.data() + 16, Desc.size() - 16));
+
+ return true;
+}
+
+template <class ELFT>
void GNUELFDumper<ELFT>::printMemtag(
const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
const ArrayRef<uint8_t> AndroidNoteDesc,
@@ -5416,8 +5521,8 @@
return {"", ""};
case ELF::NT_AMD_HSA_CODE_OBJECT_VERSION: {
struct CodeObjectVersion {
- uint32_t MajorVersion;
- uint32_t MinorVersion;
+ support::aligned_ulittle32_t MajorVersion;
+ support::aligned_ulittle32_t MinorVersion;
};
if (Desc.size() != sizeof(CodeObjectVersion))
return {"AMD HSA Code Object Version",
@@ -5431,8 +5536,8 @@
}
case ELF::NT_AMD_HSA_HSAIL: {
struct HSAILProperties {
- uint32_t HSAILMajorVersion;
- uint32_t HSAILMinorVersion;
+ support::aligned_ulittle32_t HSAILMajorVersion;
+ support::aligned_ulittle32_t HSAILMinorVersion;
uint8_t Profile;
uint8_t MachineModel;
uint8_t DefaultFloatRound;
@@ -5452,11 +5557,11 @@
}
case ELF::NT_AMD_HSA_ISA_VERSION: {
struct IsaVersion {
- uint16_t VendorNameSize;
- uint16_t ArchitectureNameSize;
- uint32_t Major;
- uint32_t Minor;
- uint32_t Stepping;
+ support::aligned_ulittle16_t VendorNameSize;
+ support::aligned_ulittle16_t ArchitectureNameSize;
+ support::aligned_ulittle32_t Major;
+ support::aligned_ulittle32_t Minor;
+ support::aligned_ulittle32_t Stepping;
};
if (Desc.size() < sizeof(IsaVersion))
return {"AMD HSA ISA Version", "Invalid AMD HSA ISA Version"};
@@ -5492,8 +5597,8 @@
}
case ELF::NT_AMD_PAL_METADATA: {
struct PALMetadata {
- uint32_t Key;
- uint32_t Value;
+ support::aligned_ulittle32_t Key;
+ support::aligned_ulittle32_t Value;
};
if (Desc.size() % sizeof(PALMetadata) != 0)
return {"AMD PAL Metadata", "Invalid AMD PAL Metadata"};
@@ -5530,7 +5635,7 @@
// FIXME: Metadata Verifier only works with AMDHSA.
// This is an ugly workaround to avoid the verifier for other MD
// formats (e.g. amdpal)
- if (MsgPackString.find("amdhsa.") != StringRef::npos) {
+ if (MsgPackString.contains("amdhsa.")) {
AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true);
if (!Verifier.verify(MsgPackDoc.getRoot()))
MetadataString = "Invalid AMDGPU Metadata\n";
@@ -5709,6 +5814,10 @@
"NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)"},
};
+const NoteType ARMNoteTypes[] = {
+ {ELF::NT_ARM_TYPE_PAUTH_ABI_TAG, "NT_ARM_TYPE_PAUTH_ABI_TAG"},
+};
+
const NoteType CoreNoteTypes[] = {
{ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"},
{ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"},
@@ -5771,6 +5880,8 @@
{ELF::NT_ARM_SVE, "NT_ARM_SVE (AArch64 SVE registers)"},
{ELF::NT_ARM_PAC_MASK,
"NT_ARM_PAC_MASK (AArch64 Pointer Authentication code masks)"},
+ {ELF::NT_ARM_TAGGED_ADDR_CTRL,
+ "NT_ARM_TAGGED_ADDR_CTRL (AArch64 Tagged Address Control)"},
{ELF::NT_ARM_SSVE, "NT_ARM_SSVE (AArch64 Streaming SVE registers)"},
{ELF::NT_ARM_ZA, "NT_ARM_ZA (AArch64 SME ZA registers)"},
{ELF::NT_ARM_ZT, "NT_ARM_ZT (AArch64 SME ZT registers)"},
@@ -5804,13 +5915,13 @@
return FindNote(FreeBSDNoteTypes);
}
}
- if (ELFType == ELF::ET_CORE && Name.startswith("NetBSD-CORE")) {
+ if (ELFType == ELF::ET_CORE && Name.starts_with("NetBSD-CORE")) {
StringRef Result = FindNote(NetBSDCoreNoteTypes);
if (!Result.empty())
return Result;
return FindNote(CoreNoteTypes);
}
- if (ELFType == ELF::ET_CORE && Name.startswith("OpenBSD")) {
+ if (ELFType == ELF::ET_CORE && Name.starts_with("OpenBSD")) {
// OpenBSD also places the generic core notes in the OpenBSD namespace.
StringRef Result = FindNote(OpenBSDCoreNoteTypes);
if (!Result.empty())
@@ -5825,6 +5936,8 @@
return FindNote(LLVMOMPOFFLOADNoteTypes);
if (Name == "Android")
return FindNote(AndroidNoteTypes);
+ if (Name == "ARM")
+ return FindNote(ARMNoteTypes);
if (ELFType == ELF::ET_CORE)
return FindNote(CoreNoteTypes);
@@ -5967,9 +6080,9 @@
return Error::success();
} else if (Name == "CORE") {
if (Type == ELF::NT_FILE) {
- DataExtractor DescExtractor(Descriptor,
- ELFT::TargetEndianness == support::little,
- sizeof(Elf_Addr));
+ DataExtractor DescExtractor(
+ Descriptor, ELFT::TargetEndianness == llvm::endianness::little,
+ sizeof(Elf_Addr));
if (Expected<CoreNote> NoteOrErr = readCoreNote(DescExtractor)) {
printCoreNote<ELFT>(OS, *NoteOrErr);
return Error::success();
@@ -5980,6 +6093,9 @@
} else if (Name == "Android") {
if (printAndroidNote(OS, Type, Descriptor))
return Error::success();
+ } else if (Name == "ARM") {
+ if (printAArch64Note<ELFT>(OS, Type, Descriptor))
+ return Error::success();
}
if (!Descriptor.empty()) {
OS << " description data:";
@@ -6172,11 +6288,13 @@
toString(std::move(E)));
};
- // SHT_RELR/SHT_ANDROID_RELR sections do not have an associated symbol table.
- // For them we should not treat the value of the sh_link field as an index of
- // a symbol table.
+ // SHT_RELR/SHT_ANDROID_RELR/SHT_AARCH64_AUTH_RELR sections do not have an
+ // associated symbol table. For them we should not treat the value of the
+ // sh_link field as an index of a symbol table.
const Elf_Shdr *SymTab;
- if (Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_RELR) {
+ if (Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_RELR &&
+ !(Obj.getHeader().e_machine == EM_AARCH64 &&
+ Sec.sh_type == ELF::SHT_AARCH64_AUTH_RELR)) {
Expected<const Elf_Shdr *> SymTabOrErr = Obj.getSection(Sec.sh_link);
if (!SymTabOrErr) {
Warn(SymTabOrErr.takeError(), "unable to locate a symbol table for");
@@ -6204,6 +6322,10 @@
Warn(RangeOrErr.takeError());
}
break;
+ case ELF::SHT_AARCH64_AUTH_RELR:
+ if (Obj.getHeader().e_machine != EM_AARCH64)
+ break;
+ [[fallthrough]];
case ELF::SHT_RELR:
case ELF::SHT_ANDROID_RELR: {
Expected<Elf_Relr_Range> RangeOrErr = Obj.relrs(Sec);
@@ -6841,6 +6963,9 @@
else if (E.e_machine == EM_XTENSA)
W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderXtensaFlags),
unsigned(ELF::EF_XTENSA_MACH));
+ else if (E.e_machine == EM_CUDA)
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderNVPTXFlags),
+ unsigned(ELF::EF_CUDA_SM));
else
W.printFlags("Flags", E.e_flags);
W.printNumber("HeaderSize", E.e_ehsize);
@@ -6900,7 +7025,7 @@
ListScope D(W, "Relocations");
for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) {
- if (!isRelocationSec<ELFT>(Sec))
+ if (!isRelocationSec<ELFT>(Sec, this->Obj.getHeader()))
continue;
StringRef Name = this->getPrintableSectionName(Sec);
@@ -7011,7 +7136,8 @@
this->Obj.getSection(Sym, this->DotSymtabSec, ShndxTable));
if (SymSec == &Sec)
printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false,
- false);
+ /*NonVisibilityBitsUsed=*/false,
+ /*ExtraSymInfo=*/false);
}
}
}
@@ -7098,7 +7224,8 @@
DataRegion<Elf_Word> ShndxTable,
std::optional<StringRef> StrTable,
bool IsDynamic,
- bool /*NonVisibilityBitsUsed*/) const {
+ bool /*NonVisibilityBitsUsed*/,
+ bool /*ExtraSymInfo*/) const {
std::string FullSymbolName = this->getFullSymbolName(
Symbol, SymIndex, ShndxTable, StrTable, IsDynamic);
unsigned char SymbolType = Symbol.getType();
@@ -7122,14 +7249,15 @@
template <class ELFT>
void LLVMELFDumper<ELFT>::printSymbols(bool PrintSymbols,
- bool PrintDynamicSymbols) {
+ bool PrintDynamicSymbols,
+ bool ExtraSymInfo) {
if (PrintSymbols) {
ListScope Group(W, "Symbols");
- this->printSymbolsHelper(false);
+ this->printSymbolsHelper(false, ExtraSymInfo);
}
if (PrintDynamicSymbols) {
ListScope Group(W, "DynamicSymbols");
- this->printSymbolsHelper(true);
+ this->printSymbolsHelper(true, ExtraSymInfo);
}
}
@@ -7471,7 +7599,7 @@
W.printBoolean("HasTailCall", BBE.hasTailCall());
W.printBoolean("IsEHPad", BBE.isEHPad());
W.printBoolean("CanFallThrough", BBE.canFallThrough());
- W.printBoolean("HasIndirectBranch", BBE.MD.HasIndirectBranch);
+ W.printBoolean("HasIndirectBranch", BBE.hasIndirectBranch());
}
}
}
@@ -7539,6 +7667,29 @@
}
template <class ELFT>
+static bool printAarch64NoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
+ ScopedPrinter &W) {
+ if (NoteType != NT_ARM_TYPE_PAUTH_ABI_TAG)
+ return false;
+
+ if (Desc.size() < 16)
+ return false;
+
+ uint64_t platform =
+ support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 0);
+ uint64_t version =
+ support::endian::read64<ELFT::TargetEndianness>(Desc.data() + 8);
+ W.printNumber("Platform", platform);
+ W.printNumber("Version", version);
+
+ if (Desc.size() > 16)
+ W.printString("Additional info",
+ toHex(ArrayRef<uint8_t>(Desc.data() + 16, Desc.size() - 16)));
+
+ return true;
+}
+
+template <class ELFT>
void LLVMELFDumper<ELFT>::printMemtag(
const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
const ArrayRef<uint8_t> AndroidNoteDesc,
@@ -7661,9 +7812,9 @@
return Error::success();
} else if (Name == "CORE") {
if (Type == ELF::NT_FILE) {
- DataExtractor DescExtractor(Descriptor,
- ELFT::TargetEndianness == support::little,
- sizeof(Elf_Addr));
+ DataExtractor DescExtractor(
+ Descriptor, ELFT::TargetEndianness == llvm::endianness::little,
+ sizeof(Elf_Addr));
if (Expected<CoreNote> N = readCoreNote(DescExtractor)) {
printCoreNoteLLVMStyle(*N, W);
return Error::success();
@@ -7674,6 +7825,9 @@
} else if (Name == "Android") {
if (printAndroidNoteLLVMStyle(Type, Descriptor, W))
return Error::success();
+ } else if (Name == "ARM") {
+ if (printAarch64NoteLLVMStyle<ELFT>(Type, Descriptor, W))
+ return Error::success();
}
if (!Descriptor.empty()) {
W.printBinaryBlock("Description data", Descriptor);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp
index 5b38501..0a23ad7 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -59,7 +59,7 @@
StringRef getSymbolName(const SymbolRef &Symbol) const;
uint8_t getSymbolType(const SymbolRef &Symbol) const;
- void printSymbols() override;
+ void printSymbols(bool ExtraSymInfo) override;
void printSymbols(std::optional<SymbolComparator> SymComp) override;
void printDynamicSymbols() override;
void printDynamicSymbols(std::optional<SymbolComparator> SymComp) override;
@@ -632,7 +632,9 @@
return getSymbolType(LHS) < getSymbolType(RHS);
}
-void MachODumper::printSymbols() { printSymbols(std::nullopt); }
+void MachODumper::printSymbols(bool /*ExtraSymInfo*/) {
+ printSymbols(std::nullopt);
+}
void MachODumper::printSymbols(std::optional<SymbolComparator> SymComp) {
ListScope Group(W, "Symbols");
@@ -732,10 +734,10 @@
if (Obj->isLittleEndian())
prettyPrintStackMap(
- W, StackMapParser<support::little>(StackMapContentsArray));
+ W, StackMapParser<llvm::endianness::little>(StackMapContentsArray));
else
prettyPrintStackMap(
- W, StackMapParser<support::big>(StackMapContentsArray));
+ W, StackMapParser<llvm::endianness::big>(StackMapContentsArray));
}
void MachODumper::printCGProfile() {
@@ -758,8 +760,8 @@
StringRef CGProfileContents =
unwrapOrError(Obj->getFileName(), CGProfileSection.getContents());
BinaryStreamReader Reader(CGProfileContents, Obj->isLittleEndian()
- ? llvm::support::little
- : llvm::support::big);
+ ? llvm::endianness::little
+ : llvm::endianness::big);
ListScope L(W, "CGProfile");
while (!Reader.empty()) {
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp
index 6dde372..0d3fea7 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -14,10 +14,12 @@
#include "ObjDumper.h"
#include "llvm-readobj.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/Decompressor.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
@@ -141,8 +143,23 @@
return Ret;
}
+static void maybeDecompress(const object::ObjectFile &Obj,
+ StringRef SectionName, StringRef &SectionContent,
+ SmallString<0> &Out) {
+ Expected<object::Decompressor> Decompressor = object::Decompressor::create(
+ SectionName, SectionContent, Obj.isLittleEndian(), Obj.is64Bit());
+ if (!Decompressor)
+ reportWarning(Decompressor.takeError(), Obj.getFileName());
+ else if (auto Err = Decompressor->resizeAndDecompress(Out))
+ reportWarning(std::move(Err), Obj.getFileName());
+ else
+ SectionContent = Out;
+}
+
void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj,
- ArrayRef<std::string> Sections) {
+ ArrayRef<std::string> Sections,
+ bool Decompress) {
+ SmallString<0> Out;
bool First = true;
for (object::SectionRef Section :
getSectionRefsByNameOrIndex(Obj, Sections)) {
@@ -155,12 +172,16 @@
StringRef SectionContent =
unwrapOrError(Obj.getFileName(), Section.getContents());
+ if (Decompress && Section.isCompressed())
+ maybeDecompress(Obj, SectionName, SectionContent, Out);
printAsStringList(SectionContent);
}
}
void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj,
- ArrayRef<std::string> Sections) {
+ ArrayRef<std::string> Sections,
+ bool Decompress) {
+ SmallString<0> Out;
bool First = true;
for (object::SectionRef Section :
getSectionRefsByNameOrIndex(Obj, Sections)) {
@@ -173,6 +194,8 @@
StringRef SectionContent =
unwrapOrError(Obj.getFileName(), Section.getContents());
+ if (Decompress && Section.isCompressed())
+ maybeDecompress(Obj, SectionName, SectionContent, Out);
const uint8_t *SecContent = SectionContent.bytes_begin();
const uint8_t *SecEnd = SecContent + SectionContent.size();
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h b/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h
index 921792f..3958dd3 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h
@@ -13,9 +13,7 @@
#include <memory>
#include <system_error>
-#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
@@ -77,13 +75,15 @@
virtual void printFileHeaders() = 0;
virtual void printSectionHeaders() = 0;
virtual void printRelocations() = 0;
- virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) {
+ virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+ bool ExtraSymInfo) {
if (PrintSymbols)
- printSymbols();
+ printSymbols(ExtraSymInfo);
if (PrintDynamicSymbols)
printDynamicSymbols();
}
virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+ bool ExtraSymInfo,
std::optional<SymbolComparator> SymComp) {
if (SymComp) {
if (PrintSymbols)
@@ -91,7 +91,7 @@
if (PrintDynamicSymbols)
printDynamicSymbols(SymComp);
} else {
- printSymbols(PrintSymbols, PrintDynamicSymbols);
+ printSymbols(PrintSymbols, PrintDynamicSymbols, ExtraSymInfo);
}
}
virtual void printProgramHeaders(bool PrintProgramHeaders,
@@ -175,9 +175,9 @@
void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0);
void printSectionsAsString(const object::ObjectFile &Obj,
- ArrayRef<std::string> Sections);
+ ArrayRef<std::string> Sections, bool Decompress);
void printSectionsAsHex(const object::ObjectFile &Obj,
- ArrayRef<std::string> Sections);
+ ArrayRef<std::string> Sections, bool Decompress);
std::function<Error(const Twine &Msg)> WarningHandler;
void reportUniqueWarning(Error Err) const;
@@ -187,7 +187,7 @@
ScopedPrinter &W;
private:
- virtual void printSymbols() {}
+ virtual void printSymbols(bool ExtraSymInfo) {}
virtual void printSymbols(std::optional<SymbolComparator> Comp) {}
virtual void printDynamicSymbols() {}
virtual void printDynamicSymbols(std::optional<SymbolComparator> Comp) {}
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/Opts.td b/src/llvm-project/llvm/tools/llvm-readobj/Opts.td
index fec0adb..018facc 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/Opts.td
+++ b/src/llvm-project/llvm/tools/llvm-readobj/Opts.td
@@ -20,11 +20,13 @@
def arch_specific : FF<"arch-specific", "Display architecture-specific information">;
def bb_addr_map : FF<"bb-addr-map", "Display the BB address map section">;
def cg_profile : FF<"cg-profile", "Display call graph profile section">;
+def decompress : FF<"decompress", "Dump decompressed section content when used with -x or -p">;
defm demangle : BB<"demangle", "Demangle symbol names", "Do not demangle symbol names (default)">;
def dependent_libraries : FF<"dependent-libraries", "Display the dependent libraries section">;
def dyn_relocations : FF<"dyn-relocations", "Display the dynamic relocation entries in the file">;
def dyn_syms : FF<"dyn-syms", "Display the dynamic symbol table">;
def expand_relocs : FF<"expand-relocs", "Expand each shown relocation to multiple lines">;
+def extra_sym_info : FF<"extra-sym-info", "Display extra information when showing symbols">;
def file_header : FF<"file-header", "Display file header">;
def headers : FF<"headers", "Equivalent to setting: --file-header, --program-headers, --section-headers">;
defm hex_dump : Eq<"hex-dump", "Display the specified section(s) as hexadecimal bytes">, MetaVarName<"<name or index>">;
@@ -135,5 +137,7 @@
def : F<"s", "Alias for --symbols">, Alias<symbols>;
def : F<"t", "Alias for --section-details">, Alias<section_details>;
def : F<"u", "Alias for --unwind">, Alias<unwind>;
+def : F<"X", "Alias for --extra-sym-info">, Alias<extra_sym_info>, Group<grp_elf>;
def : F<"V", "Alias for --version-info">, Alias<version_info>, Group<grp_elf>;
def : JoinedOrSeparate<["-"], "x">, Alias<hex_dump_EQ>, HelpText<"Alias for --hex-dump">, MetaVarName<"<name or index>">;
+def : F<"z", "Alias for --decompress">, Alias<decompress>;
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp
index e6f0ac7..5d7639b 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -70,7 +70,7 @@
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
private:
- void printSymbols() override;
+ void printSymbols(bool ExtraSymInfo) override;
void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
const WasmObjectFile *Obj;
@@ -144,7 +144,7 @@
}
}
-void WasmDumper::printSymbols() {
+void WasmDumper::printSymbols(bool /*ExtraSymInfo*/) {
ListScope Group(W, "Symbols");
for (const SymbolRef &Symbol : Obj->symbols())
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
index 2896f20..e4bd772 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -397,7 +397,7 @@
else
consumeError(NameOrErr.takeError());
- if (Name != ".pdata" && !Name.startswith(".pdata$"))
+ if (Name != ".pdata" && !Name.starts_with(".pdata$"))
continue;
const coff_section *PData = Ctx.COFF.getCOFFSection(Section);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
index fb085ec..5337005 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
@@ -26,7 +26,7 @@
for (UTF16 Ch : UTF16Str) {
// UTF16Str will have swapped byte order in case of big-endian machines.
// Swap it back in such a case.
- uint16_t ChValue = support::endian::byte_swap(Ch, support::little);
+ uint16_t ChValue = support::endian::byte_swap(Ch, llvm::endianness::little);
if (ChValue <= 0xFF)
Result += ChValue;
else
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp
index 74ebcc4..8ebd670 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -33,7 +33,7 @@
void printAuxiliaryHeader() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
+ void printSymbols(bool ExtraSymInfo) override;
void printDynamicSymbols() override;
void printUnwindInfo() override;
void printStackMap() const override;
@@ -903,7 +903,7 @@
}
}
-void XCOFFDumper::printSymbols() {
+void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
ListScope Group(W, "Symbols");
for (const SymbolRef &S : Obj.symbols())
printSymbol(S);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp b/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp
index d72eec0..979433d 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -42,7 +42,6 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -55,9 +54,7 @@
using namespace llvm::opt; // for HelpHidden in Opts.inc
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -70,13 +67,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -106,10 +97,12 @@
static bool BBAddrMap;
bool ExpandRelocs;
static bool CGProfile;
+static bool Decompress;
bool Demangle;
static bool DependentLibraries;
static bool DynRelocs;
static bool DynamicSymbols;
+static bool ExtraSymInfo;
static bool FileHeaders;
static bool Headers;
static std::vector<std::string> HexDump;
@@ -220,11 +213,13 @@
opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific);
opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map);
opts::CGProfile = Args.hasArg(OPT_cg_profile);
+ opts::Decompress = Args.hasArg(OPT_decompress);
opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries);
opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
opts::DynamicSymbols = Args.hasArg(OPT_dyn_syms);
opts::ExpandRelocs = Args.hasArg(OPT_expand_relocs);
+ opts::ExtraSymInfo = Args.hasArg(OPT_extra_sym_info);
opts::FileHeaders = Args.hasArg(OPT_file_header);
opts::Headers = Args.hasArg(OPT_headers);
opts::HexDump = Args.getAllArgValues(OPT_hex_dump_EQ);
@@ -443,11 +438,12 @@
if (opts::UnwindInfo)
Dumper->printUnwindInfo();
if (opts::Symbols || opts::DynamicSymbols)
- Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols, SymComp);
+ Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols,
+ opts::ExtraSymInfo, SymComp);
if (!opts::StringDump.empty())
- Dumper->printSectionsAsString(Obj, opts::StringDump);
+ Dumper->printSectionsAsString(Obj, opts::StringDump, opts::Decompress);
if (!opts::HexDump.empty())
- Dumper->printSectionsAsHex(Obj, opts::HexDump);
+ Dumper->printSectionsAsHex(Obj, opts::HexDump, opts::Decompress);
if (opts::HashTable)
Dumper->printHashTable();
if (opts::GnuHashTable)
@@ -638,7 +634,6 @@
}
int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
ReadobjOptTable Tbl;
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h b/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h
index 5a9fe28..532e43d 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -16,7 +16,6 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
-#include <string>
namespace llvm {
namespace object {
diff --git a/src/llvm-project/llvm/tools/llvm-readtapi/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-readtapi/CMakeLists.txt
new file mode 100644
index 0000000..855a147
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-readtapi/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS
+ BinaryFormat
+ Object
+ Support
+ Option
+ TextAPI
+ TextAPIBinaryReader
+ )
+
+set(LLVM_TARGET_DEFINITIONS TapiOpts.td)
+tablegen(LLVM TapiOpts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ReadTAPIOptsTableGen)
+
+add_llvm_tool(llvm-readtapi
+ llvm-readtapi.cpp
+ DiffEngine.cpp
+
+ DEPENDS
+ ReadTAPIOptsTableGen
+ )
+
+if(LLVM_INSTALL_BINUTILS_SYMLINKS)
+ add_llvm_tool_symlink(readtapi llvm-readtapi)
+endif()
diff --git a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp b/src/llvm-project/llvm/tools/llvm-readtapi/DiffEngine.cpp
similarity index 93%
rename from src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
rename to src/llvm-project/llvm/tools/llvm-readtapi/DiffEngine.cpp
index 3e07bb9..40722d2 100644
--- a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readtapi/DiffEngine.cpp
@@ -224,7 +224,7 @@
Order);
diffAttribute("Parent Umbrellas", Output, Interface->umbrellas(), Order);
diffAttribute("Symbols", Output, Interface->symbols(), Order);
- for (auto Doc : Interface->documents()) {
+ for (const auto &Doc : Interface->documents()) {
DiffOutput Documents("Inlined Reexported Frameworks/Libraries");
Documents.Kind = AD_Inline_Doc;
Documents.Values.push_back(std::make_unique<InlineDoc>(
@@ -363,11 +363,30 @@
rhs, IFRHS->isApplicationExtensionSafe()),
"Application Extension Safe"));
+ if (IFLHS->hasSimulatorSupport() != IFRHS->hasSimulatorSupport())
+ Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ lhs, IFLHS->hasSimulatorSupport()),
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ rhs, IFRHS->hasSimulatorSupport()),
+ "Simulator Support"));
+
+ if (IFLHS->isOSLibNotForSharedCache() != IFRHS->isOSLibNotForSharedCache())
+ Output.push_back(
+ recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ lhs, IFLHS->isOSLibNotForSharedCache()),
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ rhs, IFRHS->isOSLibNotForSharedCache()),
+ "Shared Cache Ineligible"));
+
if (IFLHS->reexportedLibraries() != IFRHS->reexportedLibraries())
Output.push_back(recordDifferences(IFLHS->reexportedLibraries(),
IFRHS->reexportedLibraries(),
"Reexported Libraries"));
+ if (IFLHS->rpaths() != IFRHS->rpaths())
+ Output.push_back(recordDifferences(IFLHS->rpaths(), IFRHS->rpaths(),
+ "Run Path Search Paths"));
+
if (IFLHS->allowableClients() != IFRHS->allowableClients())
Output.push_back(recordDifferences(IFLHS->allowableClients(),
IFRHS->allowableClients(),
@@ -440,11 +459,11 @@
template <typename T> void sortTargetValues(std::vector<T> &TargValues) {
llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
+ if (ValA.getOrder() == ValB.getOrder()) {
+ return ValA.getVal() < ValB.getVal();
+ }
return ValA.getOrder() < ValB.getOrder();
});
- llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
- return ValA.getOrder() == ValB.getOrder() && ValA.getVal() < ValB.getVal();
- });
}
template <typename T>
@@ -541,13 +560,11 @@
}
bool DiffEngine::compareFiles(raw_ostream &OS) {
- const auto *IFLHS = &(FileLHS->getInterfaceFile());
- const auto *IFRHS = &(FileRHS->getInterfaceFile());
- if (*IFLHS == *IFRHS)
+ if (*FileLHS == *FileRHS)
return false;
- OS << "< " << std::string(IFLHS->getPath().data()) << "\n> "
- << std::string(IFRHS->getPath().data()) << "\n\n";
- std::vector<DiffOutput> Diffs = findDifferences(IFLHS, IFRHS);
+ OS << "< " << std::string(FileLHS->getPath().data()) << "\n> "
+ << std::string(FileRHS->getPath().data()) << "\n\n";
+ std::vector<DiffOutput> Diffs = findDifferences(FileLHS, FileRHS);
printDifferences(OS, Diffs, 0);
return true;
}
diff --git a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h b/src/llvm-project/llvm/tools/llvm-readtapi/DiffEngine.h
similarity index 96%
rename from src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h
rename to src/llvm-project/llvm/tools/llvm-readtapi/DiffEngine.h
index 27b7257..5f7c29c 100644
--- a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h
+++ b/src/llvm-project/llvm/tools/llvm-readtapi/DiffEngine.h
@@ -141,14 +141,14 @@
/// output of the differences found in the files.
class DiffEngine {
public:
- DiffEngine(object::TapiUniversal *InputFileNameLHS,
- object::TapiUniversal *InputFileNameRHS)
+ DiffEngine(MachO::InterfaceFile *InputFileNameLHS,
+ MachO::InterfaceFile *InputFileNameRHS)
: FileLHS(InputFileNameLHS), FileRHS(InputFileNameRHS){};
bool compareFiles(raw_ostream &);
private:
- object::TapiUniversal *FileLHS;
- object::TapiUniversal *FileRHS;
+ MachO::InterfaceFile *FileLHS;
+ MachO::InterfaceFile *FileRHS;
/// Function that prints the differences found in the files.
void printDifferences(raw_ostream &, const std::vector<DiffOutput> &, int);
diff --git a/src/llvm-project/llvm/tools/llvm-readtapi/TapiOpts.td b/src/llvm-project/llvm/tools/llvm-readtapi/TapiOpts.td
new file mode 100644
index 0000000..34ec561
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-readtapi/TapiOpts.td
@@ -0,0 +1,34 @@
+// Include the common option parsing interfaces.
+include "llvm/Option/OptParser.td"
+
+class FF<string name, string help>: Flag<["-", "--"], name>, HelpText<help>;
+multiclass JS<string name, string help, string var = ""> {
+ def NAME #_EQ : Joined<["--"], name #"=">, HelpText<help>, MetaVarName<var>;
+ def : Separate<["-", "--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
+}
+
+//
+// Top level operations
+//
+def action_group : OptionGroup<"action group">, HelpText<"COMMANDS">;
+def compare : FF<"compare", "compare tapi files for library differences">, Group<action_group>;
+def merge : FF<"merge", "merge the input files that represent the same library">, Group<action_group>;
+def extract: FF<"extract", "extract <architecture> from input file">, Group<action_group>;
+def remove: FF<"remove", "remove <architecture> from input file">, Group<action_group>;
+def stubify: FF<"stubify", "create a tapi file from a dynamic library or framework">, Group<action_group>;
+
+//
+// General Driver options
+//
+def help : FF<"help", "display this help">;
+def version: FF<"version", "print the llvm-readtapi version">;
+def v: FF<"v", "alias for --version">, Alias<version>;
+defm output: JS<"o", "write output to <file>","<file>">;
+def compact: FF<"compact", "write compact tapi output file">;
+defm filetype: JS<"filetype", "specify the output file type (tbd-v3, tbd-v4 or tbd-v5)","<value>">;
+defm arch: JS<"arch", "specify the <architecture>", "<architecture>">;
+
+//
+// Stub options
+//
+def delete_input : FF<"delete-input", "delete and replace input file on success">;
diff --git a/src/llvm-project/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/src/llvm-project/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
new file mode 100644
index 0000000..4bd4722
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
@@ -0,0 +1,300 @@
+//===-- llvm-readtapi.cpp - tapi file reader and transformer -----*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the command-line driver for llvm-readtapi.
+//
+//===----------------------------------------------------------------------===//
+#include "DiffEngine.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TextAPI/DylibReader.h"
+#include "llvm/TextAPI/TextAPIError.h"
+#include "llvm/TextAPI/TextAPIReader.h"
+#include "llvm/TextAPI/TextAPIWriter.h"
+#include "llvm/TextAPI/Utils.h"
+#include <cstdlib>
+
+using namespace llvm;
+using namespace MachO;
+using namespace object;
+
+#if !defined(PATH_MAX)
+#define PATH_MAX 1024
+#endif
+
+namespace {
+using namespace llvm::opt;
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "TapiOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
+#include "TapiOpts.inc"
+#undef PREFIX
+
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "TapiOpts.inc"
+#undef OPTION
+};
+
+class TAPIOptTable : public opt::GenericOptTable {
+public:
+ TAPIOptTable() : opt::GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
+};
+
+struct StubOptions {
+ bool DeleteInput = false;
+};
+
+struct Context {
+ std::vector<std::string> Inputs;
+ std::unique_ptr<llvm::raw_fd_stream> OutStream;
+ FileType WriteFT = FileType::TBD_V5;
+ StubOptions StubOpt;
+ bool Compact = false;
+ Architecture Arch = AK_unknown;
+};
+
+// Use unique exit code to differentiate failures not directly caused from
+// TextAPI operations. This is used for wrapping `compare` operations in
+// automation and scripting.
+const int NON_TAPI_EXIT_CODE = 2;
+const std::string TOOLNAME = "llvm-readtapi";
+ExitOnError ExitOnErr;
+} // anonymous namespace
+
+// Handle error reporting in cases where `ExitOnError` is not used.
+static void reportError(Twine Message, int ExitCode = EXIT_FAILURE) {
+ errs() << TOOLNAME << ": error: " << Message << "\n";
+ errs().flush();
+ exit(ExitCode);
+}
+
+static std::unique_ptr<InterfaceFile>
+getInterfaceFile(const StringRef Filename, bool ResetBanner = true) {
+ ExitOnErr.setBanner(TOOLNAME + ": error: '" + Filename.str() + "' ");
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getFile(Filename);
+ if (BufferOrErr.getError())
+ ExitOnErr(errorCodeToError(BufferOrErr.getError()));
+ auto Buffer = std::move(*BufferOrErr);
+
+ std::unique_ptr<InterfaceFile> IF;
+ switch (identify_magic(Buffer->getBuffer())) {
+ case file_magic::macho_dynamically_linked_shared_lib:
+ LLVM_FALLTHROUGH;
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
+ LLVM_FALLTHROUGH;
+ case file_magic::macho_universal_binary:
+ IF = ExitOnErr(DylibReader::get(Buffer->getMemBufferRef()));
+ break;
+ case file_magic::tapi_file:
+ IF = ExitOnErr(TextAPIReader::get(Buffer->getMemBufferRef()));
+ break;
+ default:
+ reportError(Filename + ": unsupported file type");
+ }
+
+ if (ResetBanner)
+ ExitOnErr.setBanner(TOOLNAME + ": error: ");
+ return IF;
+}
+
+static bool handleCompareAction(const Context &Ctx) {
+ if (Ctx.Inputs.size() != 2)
+ reportError("compare only supports two input files",
+ /*ExitCode=*/NON_TAPI_EXIT_CODE);
+
+ // Override default exit code.
+ ExitOnErr = ExitOnError(TOOLNAME + ": error: ",
+ /*DefaultErrorExitCode=*/NON_TAPI_EXIT_CODE);
+ auto LeftIF = getInterfaceFile(Ctx.Inputs.front());
+ auto RightIF = getInterfaceFile(Ctx.Inputs.at(1));
+
+ raw_ostream &OS = Ctx.OutStream ? *Ctx.OutStream : outs();
+ return DiffEngine(LeftIF.get(), RightIF.get()).compareFiles(OS);
+}
+
+static bool handleWriteAction(const Context &Ctx,
+ std::unique_ptr<InterfaceFile> Out = nullptr) {
+ if (!Out) {
+ if (Ctx.Inputs.size() != 1)
+ reportError("write only supports one input file");
+ Out = getInterfaceFile(Ctx.Inputs.front());
+ }
+ raw_ostream &OS = Ctx.OutStream ? *Ctx.OutStream : outs();
+ ExitOnErr(TextAPIWriter::writeToStream(OS, *Out, Ctx.WriteFT, Ctx.Compact));
+ return EXIT_SUCCESS;
+}
+
+static bool handleMergeAction(const Context &Ctx) {
+ if (Ctx.Inputs.size() < 2)
+ reportError("merge requires at least two input files");
+
+ std::unique_ptr<InterfaceFile> Out;
+ for (StringRef FileName : Ctx.Inputs) {
+ auto IF = getInterfaceFile(FileName);
+ // On the first iteration copy the input file and skip merge.
+ if (!Out) {
+ Out = std::move(IF);
+ continue;
+ }
+ Out = ExitOnErr(Out->merge(IF.get()));
+ }
+ return handleWriteAction(Ctx, std::move(Out));
+}
+
+static bool handleStubifyAction(Context &Ctx) {
+ if (Ctx.Inputs.empty())
+ reportError("stubify requires at least one input file");
+
+ if ((Ctx.Inputs.size() > 1) && (Ctx.OutStream != nullptr))
+ reportError("cannot write multiple inputs into single output file");
+
+ for (StringRef FileName : Ctx.Inputs) {
+ auto IF = getInterfaceFile(FileName);
+ if (Ctx.StubOpt.DeleteInput) {
+ std::error_code EC;
+ SmallString<PATH_MAX> OutputLoc = FileName;
+ MachO::replace_extension(OutputLoc, ".tbd");
+ Ctx.OutStream = std::make_unique<llvm::raw_fd_stream>(OutputLoc, EC);
+ if (EC)
+ reportError("opening file '" + OutputLoc + ": " + EC.message());
+ if (auto Err = sys::fs::remove(FileName))
+ reportError("deleting file '" + FileName + ": " + EC.message());
+ }
+ handleWriteAction(Ctx, std::move(IF));
+ }
+ return EXIT_SUCCESS;
+}
+
+using IFOperation =
+ std::function<llvm::Expected<std::unique_ptr<InterfaceFile>>(
+ const llvm::MachO::InterfaceFile &, Architecture)>;
+static bool handleSingleFileAction(const Context &Ctx, const StringRef Action,
+ IFOperation act) {
+ if (Ctx.Inputs.size() != 1)
+ reportError(Action + " only supports one input file");
+ if (Ctx.Arch == AK_unknown)
+ reportError(Action + " requires -arch <arch>");
+
+ auto IF = getInterfaceFile(Ctx.Inputs.front(), /*ResetBanner=*/false);
+ auto OutIF = act(*IF, Ctx.Arch);
+ if (!OutIF)
+ ExitOnErr(OutIF.takeError());
+
+ return handleWriteAction(Ctx, std::move(*OutIF));
+}
+
+static void setStubOptions(opt::InputArgList &Args, StubOptions &Opt) {
+ Opt.DeleteInput = Args.hasArg(OPT_delete_input);
+}
+
+int main(int Argc, char **Argv) {
+ InitLLVM X(Argc, Argv);
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ TAPIOptTable Tbl;
+ Context Ctx;
+ ExitOnErr.setBanner(TOOLNAME + ": error:");
+ opt::InputArgList Args = Tbl.parseArgs(
+ Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { reportError(Msg); });
+ if (Args.hasArg(OPT_help)) {
+ Tbl.printHelp(outs(),
+ "USAGE: llvm-readtapi <command> [-arch <architecture> "
+ "<options>]* <inputs> [-o "
+ "<output>]*",
+ "LLVM TAPI file reader and transformer");
+ return EXIT_SUCCESS;
+ }
+
+ if (Args.hasArg(OPT_version)) {
+ cl::PrintVersionMessage();
+ return EXIT_SUCCESS;
+ }
+
+ // TODO: Add support for picking up libraries from directory input.
+ for (opt::Arg *A : Args.filtered(OPT_INPUT))
+ Ctx.Inputs.push_back(A->getValue());
+
+ if (opt::Arg *A = Args.getLastArg(OPT_output_EQ)) {
+ std::string OutputLoc = std::move(A->getValue());
+ std::error_code EC;
+ Ctx.OutStream = std::make_unique<llvm::raw_fd_stream>(OutputLoc, EC);
+ if (EC)
+ reportError("error opening the file '" + OutputLoc + EC.message(),
+ NON_TAPI_EXIT_CODE);
+ }
+
+ Ctx.Compact = Args.hasArg(OPT_compact);
+
+ if (opt::Arg *A = Args.getLastArg(OPT_filetype_EQ)) {
+ StringRef FT = A->getValue();
+ Ctx.WriteFT = TextAPIWriter::parseFileType(FT);
+ if (Ctx.WriteFT < FileType::TBD_V3)
+ reportError("deprecated filetype '" + FT + "' is not supported to write");
+ if (Ctx.WriteFT == FileType::Invalid)
+ reportError("unsupported filetype '" + FT + "'");
+ }
+
+ if (opt::Arg *A = Args.getLastArg(OPT_arch_EQ)) {
+ StringRef Arch = A->getValue();
+ Ctx.Arch = getArchitectureFromName(Arch);
+ if (Ctx.Arch == AK_unknown)
+ reportError("unsupported architecture '" + Arch);
+ }
+ // Handle top level and exclusive operation.
+ SmallVector<opt::Arg *, 1> ActionArgs(Args.filtered(OPT_action_group));
+
+ if (ActionArgs.empty())
+ // If no action specified, write out tapi file in requested format.
+ return handleWriteAction(Ctx);
+
+ if (ActionArgs.size() > 1) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS << "only one of the following actions can be specified:";
+ for (auto *Arg : ActionArgs)
+ OS << " " << Arg->getSpelling();
+ reportError(OS.str());
+ }
+
+ switch (ActionArgs.front()->getOption().getID()) {
+ case OPT_compare:
+ return handleCompareAction(Ctx);
+ case OPT_merge:
+ return handleMergeAction(Ctx);
+ case OPT_extract:
+ return handleSingleFileAction(Ctx, "extract", &InterfaceFile::extract);
+ case OPT_remove:
+ return handleSingleFileAction(Ctx, "remove", &InterfaceFile::remove);
+ case OPT_stubify:
+ setStubOptions(Args, Ctx.StubOpt);
+ return handleStubifyAction(Ctx);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt
index 4375376..2f1164b 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt
@@ -31,6 +31,7 @@
deltas/ReduceAttributes.cpp
deltas/ReduceBasicBlocks.cpp
deltas/ReduceDIMetadata.cpp
+ deltas/ReduceDPValues.cpp
deltas/ReduceFunctionBodies.cpp
deltas/ReduceFunctions.cpp
deltas/ReduceGlobalObjects.cpp
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp b/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp
index bfe299c..56e39b8 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp
@@ -20,6 +20,7 @@
#include "deltas/ReduceAttributes.h"
#include "deltas/ReduceBasicBlocks.h"
#include "deltas/ReduceDIMetadata.h"
+#include "deltas/ReduceDPValues.h"
#include "deltas/ReduceFunctionBodies.h"
#include "deltas/ReduceFunctions.h"
#include "deltas/ReduceGlobalObjects.h"
@@ -78,9 +79,11 @@
DELTA_PASS("aliases", reduceAliasesDeltaPass) \
DELTA_PASS("ifuncs", reduceIFuncsDeltaPass) \
DELTA_PASS("simplify-conditionals-true", reduceConditionalsTrueDeltaPass) \
- DELTA_PASS("simplify-conditionals-false", reduceConditionalsFalseDeltaPass)\
+ DELTA_PASS("simplify-conditionals-false", \
+ reduceConditionalsFalseDeltaPass) \
DELTA_PASS("invokes", reduceInvokesDeltaPass) \
- DELTA_PASS("unreachable-basic-blocks", reduceUnreachableBasicBlocksDeltaPass) \
+ DELTA_PASS("unreachable-basic-blocks", \
+ reduceUnreachableBasicBlocksDeltaPass) \
DELTA_PASS("basic-blocks", reduceBasicBlocksDeltaPass) \
DELTA_PASS("simplify-cfg", reduceUsingSimplifyCFGDeltaPass) \
DELTA_PASS("function-data", reduceFunctionDataDeltaPass) \
@@ -89,6 +92,7 @@
DELTA_PASS("global-initializers", reduceGlobalsInitializersDeltaPass) \
DELTA_PASS("global-variables", reduceGlobalsDeltaPass) \
DELTA_PASS("di-metadata", reduceDIMetadataDeltaPass) \
+ DELTA_PASS("dpvalues", reduceDPValuesDeltaPass) \
DELTA_PASS("metadata", reduceMetadataDeltaPass) \
DELTA_PASS("named-metadata", reduceNamedMetadataDeltaPass) \
DELTA_PASS("arguments", reduceArgumentsDeltaPass) \
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
index 3085208..3532167 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -19,8 +19,10 @@
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/PseudoSourceValueManager.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
@@ -153,6 +155,23 @@
}
}
+static void cloneJumpTableInfo(
+ MachineFunction &DstMF, const MachineJumpTableInfo &SrcJTI,
+ const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) {
+
+ auto *DstJTI = DstMF.getOrCreateJumpTableInfo(SrcJTI.getEntryKind());
+
+ std::vector<MachineBasicBlock *> DstBBs;
+
+ for (const MachineJumpTableEntry &Entry : SrcJTI.getJumpTables()) {
+ for (MachineBasicBlock *X : Entry.MBBs)
+ DstBBs.push_back(Src2DstMBB.find(X)->second);
+
+ DstJTI->createJumpTableIndex(DstBBs);
+ DstBBs.clear();
+ }
+}
+
static void cloneMemOperands(MachineInstr &DstMI, MachineInstr &SrcMI,
MachineFunction &SrcMF, MachineFunction &DstMF) {
// The new MachineMemOperands should be owned by the new function's
@@ -225,6 +244,8 @@
DstMF->CreateMachineBasicBlock(SrcMBB.getBasicBlock());
Src2DstMBB[&SrcMBB] = DstMBB;
+ DstMBB->setCallFrameSize(SrcMBB.getCallFrameSize());
+
if (SrcMBB.isIRBlockAddressTaken())
DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock());
if (SrcMBB.isMachineBlockAddressTaken())
@@ -264,6 +285,10 @@
// Copy stack objects and other info
cloneFrameInfo(DstMFI, SrcMFI, Src2DstMBB);
+ if (MachineJumpTableInfo *SrcJTI = SrcMF->getJumpTableInfo()) {
+ cloneJumpTableInfo(*DstMF, *SrcJTI, Src2DstMBB);
+ }
+
// Remap the debug info frame index references.
DstMF->VariableDbgInfos = SrcMF->VariableDbgInfos;
@@ -762,31 +787,17 @@
auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
StringRef OldDLStr) -> std::optional<std::string> {
- // If we are supposed to override the target triple, do so now.
+ // NB: We always call createTargetMachineForTriple() even if an explicit
+ // DataLayout is already set in the module since we want to use this
+ // callback to setup the TargetMachine rather than doing it later.
std::string IRTargetTriple = DataLayoutTargetTriple.str();
if (!TargetTriple.empty())
IRTargetTriple = Triple::normalize(TargetTriple);
TheTriple = Triple(IRTargetTriple);
if (TheTriple.getTriple().empty())
TheTriple.setTriple(sys::getDefaultTargetTriple());
-
- std::string Error;
- const Target *TheTarget =
- TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
- if (!TheTarget) {
- WithColor::error(errs(), ToolName) << Error;
- exit(1);
- }
-
- // Hopefully the MIR parsing doesn't depend on any options.
- TargetOptions Options;
- std::optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
- std::string CPUStr = codegen::getCPUStr();
- std::string FeaturesStr = codegen::getFeaturesStr();
- TM = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
- TheTriple.getTriple(), CPUStr, FeaturesStr, Options, RM,
- codegen::getExplicitCodeModel(), CodeGenOpt::Default));
- assert(TM && "Could not allocate target machine!");
+ ExitOnError ExitOnErr(std::string(ToolName) + ": error: ");
+ TM = ExitOnErr(codegen::createTargetMachineForTriple(TheTriple.str()));
return TM->createDataLayout().getStringRepresentation();
};
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h b/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h
index 136cd80..16d3dcd 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h
@@ -10,7 +10,6 @@
#define LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
#include "ReducerWorkItem.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.cpp
index 46bc93c..62dfd62 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.cpp
@@ -29,7 +29,6 @@
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/ThreadPool.h"
#include <fstream>
-#include <set>
using namespace llvm;
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h
index 5b60ea6..96fcea8 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h
@@ -17,11 +17,9 @@
#include "ReducerWorkItem.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <utility>
-#include <vector>
namespace llvm {
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp
index d3572e2..5b1363d 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp
@@ -113,7 +113,7 @@
replaceFunctionCalls(*F, *ClonedFunc, ArgIndexesToKeep);
// Rename Cloned Function to Old's name
std::string FName = std::string(F->getName());
- F->replaceAllUsesWith(ConstantExpr::getBitCast(ClonedFunc, F->getType()));
+ F->replaceAllUsesWith(ClonedFunc);
F->eraseFromParent();
ClonedFunc->setName(FName);
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
index df87ce7..e643fe2 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
@@ -15,11 +15,9 @@
#include "Delta.h"
#include "TestRunner.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
@@ -32,7 +30,6 @@
#include <cassert>
#include <iterator>
#include <utility>
-#include <vector>
namespace llvm {
class LLVMContext;
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp
index bbd928a..f4d8496 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp
@@ -15,12 +15,9 @@
#include "Delta.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/InstIterator.h"
-#include <set>
-#include <stack>
#include <tuple>
#include <vector>
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDPValues.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDPValues.cpp
new file mode 100644
index 0000000..8f5bafd
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDPValues.cpp
@@ -0,0 +1,39 @@
+//===- ReduceDPValues.cpp - Specialized Delta Pass ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting DPValues from defined functions.
+//
+// DPValues store variable-location debug-info and are attached to instructions.
+// This information used to be represented by intrinsics such as dbg.value, and
+// would naturally get reduced by llvm-reduce like any other instruction. As
+// DPValues get stored elsewhere, they need to be enumerated and eliminated like
+// any other data structure in LLVM.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceDPValues.h"
+#include "Utils.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace llvm;
+
+static void extractDPValuesFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &M = WorkItem.getModule();
+
+ for (auto &F : M)
+ for (auto &BB : F)
+ for (auto &I : BB)
+ for (DPValue &DPV : llvm::make_early_inc_range(I.getDbgValueRange()))
+ if (!O.shouldKeep())
+ DPV.eraseFromParent();
+}
+
+void llvm::reduceDPValuesDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, extractDPValuesFromModule, "Reducing DPValues");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDPValues.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDPValues.h
new file mode 100644
index 0000000..34ebd27
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDPValues.h
@@ -0,0 +1,25 @@
+//===- ReduceDPValues.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting DPValues from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDPVALUES_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDPVALUES_H
+
+#include "Delta.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DebugProgramInstruction.h"
+
+namespace llvm {
+void reduceDPValuesDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
index 05127ec..619811c 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
@@ -16,10 +16,8 @@
#include "Delta.h"
#include "Utils.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <iterator>
-#include <vector>
using namespace llvm;
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp
index c73e74e..7b6fe7e 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp
@@ -30,6 +30,12 @@
} else if (auto *PE = dyn_cast<PossiblyExactOperator>(&I)) {
if (PE->isExact() && !O.shouldKeep())
I.setIsExact(false);
+ } else if (auto *NNI = dyn_cast<PossiblyNonNegInst>(&I)) {
+ if (NNI->hasNonNeg() && !O.shouldKeep())
+ NNI->setNonNeg(false);
+ } else if (auto *PDI = dyn_cast<PossiblyDisjointInst>(&I)) {
+ if (PDI->isDisjoint() && !O.shouldKeep())
+ PDI->setIsDisjoint(false);
} else if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
if (GEP->isInBounds() && !O.shouldKeep())
GEP->setIsInBounds(false);
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
index d491858..30bf612 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
@@ -17,7 +17,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
-#include <vector>
using namespace llvm;
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp
index 93992303..f8fa83e 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp
@@ -114,12 +114,6 @@
PtrArg = ConstantPointerNull::get(PtrTy);
}
- // Make sure we don't emit an invalid store with typed pointers.
- if (IsStore && DataArg->getType()->getPointerTo(
- cast<PointerType>(PtrArg->getType())->getAddressSpace()) !=
- PtrArg->getType())
- return false;
-
return true;
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp
index 6f9cafb..a211b6a 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp
@@ -18,7 +18,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Support/raw_ostream.h"
@@ -55,7 +54,7 @@
OperandBundlesToKeepIndexes.reserve(Call.getNumOperandBundles());
// Enumerate every operand bundle on this call.
- for (unsigned BundleIndex : seq(0U, Call.getNumOperandBundles()))
+ for (unsigned BundleIndex : seq(Call.getNumOperandBundles()))
if (O.shouldKeep()) // Should we keep this one?
OperandBundlesToKeepIndexes.emplace_back(BundleIndex);
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.cpp
index 52679f8..1763fee 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.cpp
@@ -14,6 +14,7 @@
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Operator.h"
+#include <queue>
using namespace llvm;
@@ -149,13 +150,13 @@
// Regardless whether referenced, add the function arguments as
// replacement possibility with the goal of reducing the number of (used)
- // function arguments, possibly created by the the operands-to-args.
+ // function arguments, possibly created by the operands-to-args.
for (Argument &Arg : F.args())
ReferencedVals.insert(&Arg);
// After all candidates have been added, it doesn't need to be a set
// anymore.
- std::vector<Value *> Candidates = ReferencedVals.takeVector();
+ auto Candidates = ReferencedVals.takeVector();
// Remove ineligible candidates.
llvm::erase_if(Candidates, [&, OpVal](Value *V) {
@@ -185,7 +186,7 @@
std::reverse(Candidates.begin(), Candidates.end());
// Independency of collectReferencedValues's idea of reductive power,
- // ensure the the partial order of IsMoreReduced is enforced.
+ // ensure the partial order of IsMoreReduced is enforced.
llvm::stable_sort(Candidates, IsMoreReduced);
Callback(Op, Candidates);
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
index 0f949ab..a04f354 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
@@ -160,7 +160,14 @@
for (Use *Op : OpsToReplace) {
Value *NewArg = OldValMap.lookup(Op->get());
auto *NewUser = cast<Instruction>(VMap.lookup(Op->getUser()));
- NewUser->setOperand(Op->getOperandNo(), NewArg);
+
+ if (PHINode *NewPhi = dyn_cast<PHINode>(NewUser)) {
+ PHINode *OldPhi = cast<PHINode>(Op->getUser());
+ BasicBlock *OldBB = OldPhi->getIncomingBlock(*Op);
+ NewPhi->setIncomingValueForBlock(cast<BasicBlock>(VMap.lookup(OldBB)),
+ NewArg);
+ } else
+ NewUser->setOperand(Op->getOperandNo(), NewArg);
}
// Replace all OldF uses with NewF.
@@ -168,7 +175,7 @@
// Rename NewF to OldF's name.
std::string FName = OldF->getName().str();
- OldF->replaceAllUsesWith(ConstantExpr::getBitCast(NewF, OldF->getType()));
+ OldF->replaceAllUsesWith(NewF);
OldF->eraseFromParent();
NewF->setName(FName);
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp
index a65e55d..c9e1261 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp
@@ -18,7 +18,7 @@
static void stripDebugInfoImpl(Oracle &O, ReducerWorkItem &WorkItem) {
Module &Program = WorkItem.getModule();
bool HasDebugInfo = any_of(Program.named_metadata(), [](NamedMDNode &NMD) {
- return NMD.getName().startswith("llvm.dbg.");
+ return NMD.getName().starts_with("llvm.dbg.");
});
if (HasDebugInfo && !O.shouldKeep())
StripDebugInfo(Program);
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp b/src/llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp
index ace5c95..71ce0ca 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp
@@ -26,7 +26,6 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
-#include <vector>
#ifdef _WIN32
#include <windows.h>
@@ -101,6 +100,13 @@
"of delta passes (default=5)"),
cl::init(5), cl::cat(LLVMReduceOptions));
+static cl::opt<bool> TryUseNewDbgInfoFormat(
+ "try-experimental-debuginfo-iterators",
+ cl::desc("Enable debuginfo iterator positions, if they're built in"),
+ cl::init(false));
+
+extern cl::opt<bool> UseNewDbgInfoFormat;
+
static codegen::RegisterCodeGenFlags CGF;
/// Turn off crash debugging features
@@ -144,6 +150,17 @@
cl::HideUnrelatedOptions({&LLVMReduceOptions, &getColorCategory()});
cl::ParseCommandLineOptions(Argc, Argv, "LLVM automatic testcase reducer.\n");
+ // RemoveDIs debug-info transition: tests may request that we /try/ to use the
+ // new debug-info format, if it's built in.
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ if (TryUseNewDbgInfoFormat) {
+ // If LLVM was built with support for this, turn the new debug-info format
+ // on.
+ UseNewDbgInfoFormat = true;
+ }
+#endif
+ (void)TryUseNewDbgInfoFormat;
+
if (Argc == 1) {
cl::PrintHelpMessage();
return 0;
@@ -158,7 +175,7 @@
if (InputLanguage != InputLanguages::None) {
if (InputLanguage == InputLanguages::MIR)
ReduceModeMIR = true;
- } else if (StringRef(InputFilename).endswith(".mir")) {
+ } else if (StringRef(InputFilename).ends_with(".mir")) {
ReduceModeMIR = true;
}
diff --git a/src/llvm-project/llvm/tools/llvm-remark-size-diff/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-remark-size-diff/CMakeLists.txt
deleted file mode 100644
index 7e6f007..0000000
--- a/src/llvm-project/llvm/tools/llvm-remark-size-diff/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-set(LLVM_LINK_COMPONENTS
- Demangle
- Remarks
- Support
- )
-
-add_llvm_tool(llvm-remark-size-diff
- RemarkSizeDiff.cpp
- )
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt
index bf044d2..48aeb93 100644
--- a/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt
@@ -5,5 +5,11 @@
)
add_llvm_tool(llvm-remarkutil
+ RemarkConvert.cpp
+ RemarkCount.cpp
+ RemarkCounter.cpp
+ RemarkSizeDiff.cpp
RemarkUtil.cpp
+ RemarkUtilHelpers.cpp
+ RemarkUtilRegistry.cpp
)
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkConvert.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkConvert.cpp
new file mode 100644
index 0000000..35d8dcd
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkConvert.cpp
@@ -0,0 +1,143 @@
+//===- RemarkConvert.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Convert remarks from bitstream to yaml and the other way around.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+extern ExitOnError ExitOnErr;
+static cl::SubCommand
+ YAML2Bitstream("yaml2bitstream",
+ "Convert YAML remarks to bitstream remarks");
+static cl::SubCommand
+ Bitstream2YAML("bitstream2yaml",
+ "Convert bitstream remarks to YAML remarks");
+
+namespace yaml2bitstream {
+/// Remark format to parse.
+static constexpr Format InputFormat = Format::YAML;
+/// Remark format to output.
+static constexpr Format OutputFormat = Format::Bitstream;
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(YAML2Bitstream)
+} // namespace yaml2bitstream
+
+namespace bitstream2yaml {
+/// Remark format to parse.
+static constexpr Format InputFormat = Format::Bitstream;
+/// Remark format to output.
+static constexpr Format OutputFormat = Format::YAML;
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(Bitstream2YAML)
+} // namespace bitstream2yaml
+
+namespace yaml2bitstream {
+/// Parses all remarks in the input YAML file.
+/// \p [out] ParsedRemarks - Filled with remarks parsed from the input file.
+/// \p [out] StrTab - A string table populated for later remark serialization.
+/// \returns Error::success() if all remarks were successfully parsed, and an
+/// Error otherwise.
+static Error
+tryParseRemarksFromYAMLFile(std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
+ StringTable &StrTab) {
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ StrTab.internalize(**MaybeRemark);
+ ParsedRemarks.push_back(std::move(*MaybeRemark));
+ }
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ return Error::success();
+}
+
+/// Reserialize a list of parsed YAML remarks into bitstream remarks.
+/// \p ParsedRemarks - A list of remarks.
+/// \p StrTab - The string table for the remarks.
+/// \returns Error::success() on success.
+static Error tryReserializeYAML2Bitstream(
+ const std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
+ StringTable &StrTab) {
+ auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ auto MaybeSerializer = createRemarkSerializer(
+ OutputFormat, SerializerMode::Standalone, OF->os(), std::move(StrTab));
+ if (!MaybeSerializer)
+ return MaybeSerializer.takeError();
+ auto Serializer = std::move(*MaybeSerializer);
+ for (const auto &Remark : ParsedRemarks)
+ Serializer->emit(*Remark);
+ OF->keep();
+ return Error::success();
+}
+
+/// Parse YAML remarks and reserialize as bitstream remarks.
+/// \returns Error::success() on success, and an Error otherwise.
+static Error tryYAML2Bitstream() {
+ StringTable StrTab;
+ std::vector<std::unique_ptr<Remark>> ParsedRemarks;
+ ExitOnErr(tryParseRemarksFromYAMLFile(ParsedRemarks, StrTab));
+ return tryReserializeYAML2Bitstream(ParsedRemarks, StrTab);
+}
+} // namespace yaml2bitstream
+
+namespace bitstream2yaml {
+/// Parse bitstream remarks and reserialize as YAML remarks.
+/// \returns An Error if reserialization fails, or Error::success() on success.
+static Error tryBitstream2YAML() {
+ // Create the serializer.
+ auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ auto MaybeSerializer = createRemarkSerializer(
+ OutputFormat, SerializerMode::Standalone, OF->os());
+ if (!MaybeSerializer)
+ return MaybeSerializer.takeError();
+
+ // Create the parser.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto Serializer = std::move(*MaybeSerializer);
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+
+ // Parse + reserialize all remarks.
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next())
+ Serializer->emit(**MaybeRemark);
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ return Error::success();
+}
+} // namespace bitstream2yaml
+
+static CommandRegistration Bitstream2YamlReg(&Bitstream2YAML,
+ bitstream2yaml::tryBitstream2YAML);
+static CommandRegistration Yaml2Bitstream(&YAML2Bitstream,
+ yaml2bitstream::tryYAML2Bitstream);
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCount.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCount.cpp
new file mode 100644
index 0000000..d08f47f
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCount.cpp
@@ -0,0 +1,159 @@
+//===- RemarkCount.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Count remarks using `instruction-count` for asm-printer remarks and
+// `annotation-count` for annotation-remarks
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+static cl::SubCommand InstructionCount(
+ "instruction-count",
+ "Function instruction count information (requires asm-printer remarks)");
+static cl::SubCommand
+ AnnotationCount("annotation-count",
+ "Collect count information from annotation remarks (uses "
+ "AnnotationRemarksPass)");
+
+namespace instructioncount {
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionCount)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionCount)
+DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(InstructionCount)
+} // namespace instructioncount
+
+namespace annotationcount {
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(AnnotationCount)
+static cl::opt<std::string> AnnotationTypeToCollect(
+ "annotation-type", cl::desc("annotation-type remark to collect count for"),
+ cl::sub(AnnotationCount));
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(AnnotationCount)
+DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(AnnotationCount)
+} // namespace annotationcount
+
+static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) {
+ return UseDebugLoc && !Remark.Loc.has_value();
+}
+
+namespace instructioncount {
+/// Outputs all instruction count remarks in the file as a CSV.
+/// \returns Error::success() on success, and an Error otherwise.
+static Error tryInstructionCount() {
+ // Create the output buffer.
+ auto MaybeOF = getOutputFileWithFlags(OutputFileName,
+ /*Flags = */ sys::fs::OF_TextWithCRLF);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ // Create a parser for the user-specified input format.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ // Emit CSV header.
+ if (UseDebugLoc)
+ OF->os() << "Source,";
+ OF->os() << "Function,InstructionCount\n";
+ // Parse all remarks. Whenever we see an instruction count remark, output
+ // the file name and the number of instructions.
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ auto &Remark = **MaybeRemark;
+ if (Remark.RemarkName != "InstructionCount")
+ continue;
+ if (shouldSkipRemark(UseDebugLoc, Remark))
+ continue;
+ auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) {
+ return Arg.Key == "NumInstructions";
+ });
+ assert(InstrCountArg != Remark.Args.end() &&
+ "Expected instruction count remarks to have a NumInstructions key?");
+ if (UseDebugLoc) {
+ std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
+ std::to_string(Remark.Loc->SourceLine) + +":" +
+ std::to_string(Remark.Loc->SourceColumn);
+ OF->os() << Loc << ",";
+ }
+ OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n";
+ }
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ OF->keep();
+ return Error::success();
+}
+} // namespace instructioncount
+
+namespace annotationcount {
+static Error tryAnnotationCount() {
+ // Create the output buffer.
+ auto MaybeOF = getOutputFileWithFlags(OutputFileName,
+ /*Flags = */ sys::fs::OF_TextWithCRLF);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+ auto OF = std::move(*MaybeOF);
+ // Create a parser for the user-specified input format.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ // Emit CSV header.
+ if (UseDebugLoc)
+ OF->os() << "Source,";
+ OF->os() << "Function,Count\n";
+ // Parse all remarks. When we see the specified remark collect the count
+ // information.
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ auto &Remark = **MaybeRemark;
+ if (Remark.RemarkName != "AnnotationSummary")
+ continue;
+ if (shouldSkipRemark(UseDebugLoc, Remark))
+ continue;
+ auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) {
+ return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect;
+ });
+ if (RemarkNameArg == Remark.Args.end())
+ continue;
+ auto *CountArg = find_if(
+ Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; });
+ assert(CountArg != Remark.Args.end() &&
+ "Expected annotation-type remark to have a count key?");
+ if (UseDebugLoc) {
+ std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
+ std::to_string(Remark.Loc->SourceLine) + +":" +
+ std::to_string(Remark.Loc->SourceColumn);
+ OF->os() << Loc << ",";
+ }
+ OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n";
+ }
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ OF->keep();
+ return Error::success();
+}
+} // namespace annotationcount
+
+static CommandRegistration
+ InstructionCountReg(&InstructionCount,
+ instructioncount::tryInstructionCount);
+static CommandRegistration Yaml2Bitstream(&AnnotationCount,
+ annotationcount::tryAnnotationCount);
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
new file mode 100644
index 0000000..dc0685f
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -0,0 +1,337 @@
+//===- RemarkCounter.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic tool to count remarks based on properties
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemarkCounter.h"
+#include "RemarkUtilRegistry.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Regex.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+static cl::SubCommand CountSub("count",
+ "Collect remarks based on specified criteria.");
+
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(CountSub)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(CountSub)
+
+static cl::list<std::string>
+ Keys("args", cl::desc("Specify remark argument/s to count by."),
+ cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);
+static cl::list<std::string> RKeys(
+ "rargs",
+ cl::desc(
+ "Specify remark argument/s to count (accepts regular expressions)."),
+ cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);
+static cl::opt<std::string>
+ RemarkNameOpt("remark-name",
+ cl::desc("Optional remark name to filter collection by."),
+ cl::ValueOptional, cl::sub(CountSub));
+static cl::opt<std::string>
+ PassNameOpt("pass-name", cl::ValueOptional,
+ cl::desc("Optional remark pass name to filter collection by."),
+ cl::sub(CountSub));
+
+static cl::opt<std::string> RemarkFilterArgByOpt(
+ "filter-arg-by", cl::desc("Optional remark arg to filter collection by."),
+ cl::ValueOptional, cl::sub(CountSub));
+static cl::opt<std::string>
+ RemarkNameOptRE("rremark-name",
+ cl::desc("Optional remark name to filter collection by "
+ "(accepts regular expressions)."),
+ cl::ValueOptional, cl::sub(CountSub));
+static cl::opt<std::string>
+ RemarkArgFilterOptRE("rfilter-arg-by",
+ cl::desc("Optional remark arg to filter collection by "
+ "(accepts regular expressions)."),
+ cl::sub(CountSub), cl::ValueOptional);
+static cl::opt<std::string>
+ PassNameOptRE("rpass-name", cl::ValueOptional,
+ cl::desc("Optional remark pass name to filter collection "
+ "by (accepts regular expressions)."),
+ cl::sub(CountSub));
+static cl::opt<Type> RemarkTypeOpt(
+ "remark-type", cl::desc("Optional remark type to filter collection by."),
+ cl::values(clEnumValN(Type::Unknown, "unknown", "UNKOWN"),
+ clEnumValN(Type::Passed, "passed", "PASSED"),
+ clEnumValN(Type::Missed, "missed", "MISSED"),
+ clEnumValN(Type::Analysis, "analysis", "ANALYSIS"),
+ clEnumValN(Type::AnalysisFPCommute, "analysis-fp-commute",
+ "ANALYSIS_FP_COMMUTE"),
+ clEnumValN(Type::AnalysisAliasing, "analysis-aliasing",
+ "ANALYSIS_ALIASING"),
+ clEnumValN(Type::Failure, "failure", "FAILURE")),
+ cl::init(Type::Failure), cl::sub(CountSub));
+static cl::opt<CountBy> CountByOpt(
+ "count-by", cl::desc("Specify the property to collect remarks by."),
+ cl::values(
+ clEnumValN(CountBy::REMARK, "remark-name",
+ "Counts individual remarks based on how many of the remark "
+ "exists."),
+ clEnumValN(CountBy::ARGUMENT, "arg",
+ "Counts based on the value each specified argument has. The "
+ "argument has to have a number value to be considered.")),
+ cl::init(CountBy::REMARK), cl::sub(CountSub));
+static cl::opt<GroupBy> GroupByOpt(
+ "group-by", cl::desc("Specify the property to group remarks by."),
+ cl::values(
+ clEnumValN(
+ GroupBy::PER_SOURCE, "source",
+ "Display the count broken down by the filepath of each remark "
+ "emitted. Requires remarks to have DebugLoc information."),
+ clEnumValN(GroupBy::PER_FUNCTION, "function",
+ "Breakdown the count by function name."),
+ clEnumValN(
+ GroupBy::PER_FUNCTION_WITH_DEBUG_LOC, "function-with-loc",
+ "Breakdown the count by function name taking into consideration "
+ "the filepath info from the DebugLoc of the remark."),
+ clEnumValN(GroupBy::TOTAL, "total",
+ "Output the total number corresponding to the count for the "
+ "provided input file.")),
+ cl::init(GroupBy::PER_SOURCE), cl::sub(CountSub));
+
+/// Look for matching argument with \p Key in \p Remark and return the parsed
+/// integer value or 0 if it is has no integer value.
+static unsigned getValForKey(StringRef Key, const Remark &Remark) {
+ auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) {
+ return Arg.Key == Key && Arg.isValInt();
+ });
+ if (RemarkArg == Remark.Args.end())
+ return 0;
+ return *RemarkArg->getValAsInt();
+}
+
+Error Filters::regexArgumentsValid() {
+ if (RemarkNameFilter && RemarkNameFilter->IsRegex)
+ if (auto E = checkRegex(RemarkNameFilter->FilterRE))
+ return E;
+ if (PassNameFilter && PassNameFilter->IsRegex)
+ if (auto E = checkRegex(PassNameFilter->FilterRE))
+ return E;
+ if (ArgFilter && ArgFilter->IsRegex)
+ if (auto E = checkRegex(ArgFilter->FilterRE))
+ return E;
+ return Error::success();
+}
+
+bool Filters::filterRemark(const Remark &Remark) {
+ if (RemarkNameFilter && !RemarkNameFilter->match(Remark.RemarkName))
+ return false;
+ if (PassNameFilter && !PassNameFilter->match(Remark.PassName))
+ return false;
+ if (RemarkTypeFilter)
+ return *RemarkTypeFilter == Remark.RemarkType;
+ if (ArgFilter) {
+ if (!any_of(Remark.Args,
+ [this](Argument Arg) { return ArgFilter->match(Arg.Val); }))
+ return false;
+ }
+ return true;
+}
+
+Error ArgumentCounter::getAllMatchingArgumentsInRemark(
+ StringRef Buffer, ArrayRef<FilterMatcher> Arguments, Filters &Filter) {
+ auto MaybeParser = createRemarkParser(InputFormat, Buffer);
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ auto &Remark = **MaybeRemark;
+ // Only collect keys from remarks included in the filter.
+ if (!Filter.filterRemark(Remark))
+ continue;
+ for (auto &Key : Arguments) {
+ for (Argument Arg : Remark.Args)
+ if (Key.match(Arg.Key) && Arg.isValInt())
+ ArgumentSetIdxMap.insert({Arg.Key, ArgumentSetIdxMap.size()});
+ }
+ }
+
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ return Error::success();
+}
+
+std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {
+ switch (Group) {
+ case GroupBy::PER_FUNCTION:
+ return Remark.FunctionName.str();
+ case GroupBy::TOTAL:
+ return "Total";
+ case GroupBy::PER_SOURCE:
+ case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
+ if (!Remark.Loc.has_value())
+ return std::nullopt;
+
+ if (Group == GroupBy::PER_FUNCTION_WITH_DEBUG_LOC)
+ return Remark.Loc->SourceFilePath.str() + ":" + Remark.FunctionName.str();
+ return Remark.Loc->SourceFilePath.str();
+ }
+ llvm_unreachable("Fully covered switch above!");
+}
+
+void ArgumentCounter::collect(const Remark &Remark) {
+ SmallVector<unsigned, 4> Row(ArgumentSetIdxMap.size());
+ std::optional<std::string> GroupByKey = getGroupByKey(Remark);
+ // Early return if we don't have a value
+ if (!GroupByKey)
+ return;
+ auto GroupVal = *GroupByKey;
+ CountByKeysMap.insert({GroupVal, Row});
+ for (auto [Key, Idx] : ArgumentSetIdxMap) {
+ auto Count = getValForKey(Key, Remark);
+ CountByKeysMap[GroupVal][Idx] += Count;
+ }
+}
+
+void RemarkCounter::collect(const Remark &Remark) {
+ std::optional<std::string> Key = getGroupByKey(Remark);
+ if (!Key.has_value())
+ return;
+ auto Iter = CountedByRemarksMap.insert({*Key, 1});
+ if (!Iter.second)
+ Iter.first->second += 1;
+}
+
+Error ArgumentCounter::print(StringRef OutputFileName) {
+ auto MaybeOF =
+ getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+
+ auto OF = std::move(*MaybeOF);
+ OF->os() << groupByToStr(Group) << ",";
+ unsigned Idx = 0;
+ for (auto [Key, _] : ArgumentSetIdxMap) {
+ OF->os() << Key;
+ if (Idx != ArgumentSetIdxMap.size() - 1)
+ OF->os() << ",";
+ Idx++;
+ }
+ OF->os() << "\n";
+ for (auto [Header, CountVector] : CountByKeysMap) {
+ OF->os() << Header << ",";
+ unsigned Idx = 0;
+ for (auto Count : CountVector) {
+ OF->os() << Count;
+ if (Idx != ArgumentSetIdxMap.size() - 1)
+ OF->os() << ",";
+ Idx++;
+ }
+ OF->os() << "\n";
+ }
+ return Error::success();
+}
+
+Error RemarkCounter::print(StringRef OutputFileName) {
+ auto MaybeOF =
+ getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
+ if (!MaybeOF)
+ return MaybeOF.takeError();
+
+ auto OF = std::move(*MaybeOF);
+ OF->os() << groupByToStr(Group) << ","
+ << "Count\n";
+ for (auto [Key, Count] : CountedByRemarksMap)
+ OF->os() << Key << "," << Count << "\n";
+ OF->keep();
+ return Error::success();
+}
+
+Expected<Filters> getRemarkFilter() {
+ // Create Filter properties.
+ std::optional<FilterMatcher> RemarkNameFilter;
+ std::optional<FilterMatcher> PassNameFilter;
+ std::optional<FilterMatcher> RemarkArgFilter;
+ std::optional<Type> RemarkType;
+ if (!RemarkNameOpt.empty())
+ RemarkNameFilter = {RemarkNameOpt, false};
+ else if (!RemarkNameOptRE.empty())
+ RemarkNameFilter = {RemarkNameOptRE, true};
+ if (!PassNameOpt.empty())
+ PassNameFilter = {PassNameOpt, false};
+ else if (!PassNameOptRE.empty())
+ PassNameFilter = {PassNameOptRE, true};
+ if (RemarkTypeOpt != Type::Failure)
+ RemarkType = RemarkTypeOpt;
+ if (!RemarkFilterArgByOpt.empty())
+ RemarkArgFilter = {RemarkFilterArgByOpt, false};
+ else if (!RemarkArgFilterOptRE.empty())
+ RemarkArgFilter = {RemarkArgFilterOptRE, true};
+ // Create RemarkFilter.
+ return Filters::createRemarkFilter(std::move(RemarkNameFilter),
+ std::move(PassNameFilter),
+ std::move(RemarkArgFilter), RemarkType);
+}
+
+Error useCollectRemark(StringRef Buffer, Counter &Counter, Filters &Filter) {
+ // Create Parser.
+ auto MaybeParser = createRemarkParser(InputFormat, Buffer);
+ if (!MaybeParser)
+ return MaybeParser.takeError();
+ auto &Parser = **MaybeParser;
+ auto MaybeRemark = Parser.next();
+ for (; MaybeRemark; MaybeRemark = Parser.next()) {
+ const Remark &Remark = **MaybeRemark;
+ if (Filter.filterRemark(Remark))
+ Counter.collect(Remark);
+ }
+
+ if (auto E = Counter.print(OutputFileName))
+ return E;
+ auto E = MaybeRemark.takeError();
+ if (!E.isA<EndOfFileError>())
+ return E;
+ consumeError(std::move(E));
+ return Error::success();
+}
+
+static Error collectRemarks() {
+ // Create a parser for the user-specified input format.
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ StringRef Buffer = (*MaybeBuf)->getBuffer();
+ auto MaybeFilter = getRemarkFilter();
+ if (!MaybeFilter)
+ return MaybeFilter.takeError();
+ auto &Filter = *MaybeFilter;
+ if (CountByOpt == CountBy::REMARK) {
+ RemarkCounter RC(GroupByOpt);
+ if (auto E = useCollectRemark(Buffer, RC, Filter))
+ return E;
+ } else if (CountByOpt == CountBy::ARGUMENT) {
+ SmallVector<FilterMatcher, 4> ArgumentsVector;
+ if (!Keys.empty()) {
+ for (auto &Key : Keys)
+ ArgumentsVector.push_back({Key, false});
+ } else if (!RKeys.empty())
+ for (auto Key : RKeys)
+ ArgumentsVector.push_back({Key, true});
+ else
+ ArgumentsVector.push_back({".*", true});
+
+ Expected<ArgumentCounter> AC = ArgumentCounter::createArgumentCounter(
+ GroupByOpt, ArgumentsVector, Buffer, Filter);
+ if (!AC)
+ return AC.takeError();
+ if (auto E = useCollectRemark(Buffer, *AC, Filter))
+ return E;
+ }
+ return Error::success();
+}
+
+static CommandRegistration CountReg(&CountSub, collectRemarks);
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.h b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.h
new file mode 100644
index 0000000..34d5bff
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -0,0 +1,215 @@
+//===- RemarkCounter.h ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic tool to count remarks based on properties
+//
+//===----------------------------------------------------------------------===//
+#ifndef TOOLS_LLVM_REMARKCOUNTER_H
+#define TOOLS_LLVM_REMARKCOUNTER_H
+#include "RemarkUtilHelpers.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Support/Regex.h"
+
+namespace llvm {
+namespace remarks {
+
+/// Collect remarks by counting the existance of a remark or by looking through
+/// the keys and summing through the total count.
+enum class CountBy { REMARK, ARGUMENT };
+
+/// Summarize the count by either emitting one count for the remark file, or
+/// grouping the count by source file or by function name.
+enum class GroupBy {
+ TOTAL,
+ PER_SOURCE,
+ PER_FUNCTION,
+ PER_FUNCTION_WITH_DEBUG_LOC
+};
+
+/// Convert \p GroupBy to a std::string.
+inline std::string groupByToStr(GroupBy GroupBy) {
+ switch (GroupBy) {
+ default:
+ return "Total";
+ case GroupBy::PER_FUNCTION:
+ return "Function";
+ case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
+ return "FuctionWithDebugLoc";
+ case GroupBy::PER_SOURCE:
+ return "Source";
+ }
+}
+
+/// Filter object which can be either a string or a regex to match with the
+/// remark properties.
+struct FilterMatcher {
+ Regex FilterRE;
+ std::string FilterStr;
+ bool IsRegex;
+ FilterMatcher(std::string Filter, bool IsRegex) : IsRegex(IsRegex) {
+ if (IsRegex)
+ FilterRE = Regex(Filter);
+ else
+ FilterStr = Filter;
+ }
+
+ bool match(StringRef StringToMatch) const {
+ if (IsRegex)
+ return FilterRE.match(StringToMatch);
+ return FilterStr == StringToMatch.trim().str();
+ }
+};
+
+/// Filter out remarks based on remark properties based on name, pass name,
+/// argument and type.
+struct Filters {
+ std::optional<FilterMatcher> RemarkNameFilter;
+ std::optional<FilterMatcher> PassNameFilter;
+ std::optional<FilterMatcher> ArgFilter;
+ std::optional<Type> RemarkTypeFilter;
+ /// Returns a filter object if all the arguments provided are valid regex
+ /// types otherwise return an error.
+ static Expected<Filters>
+ createRemarkFilter(std::optional<FilterMatcher> RemarkNameFilter,
+ std::optional<FilterMatcher> PassNameFilter,
+ std::optional<FilterMatcher> ArgFilter,
+ std::optional<Type> RemarkTypeFilter) {
+ Filters Filter;
+ Filter.RemarkNameFilter = std::move(RemarkNameFilter);
+ Filter.PassNameFilter = std::move(PassNameFilter);
+ Filter.ArgFilter = std::move(ArgFilter);
+ Filter.RemarkTypeFilter = std::move(RemarkTypeFilter);
+ if (auto E = Filter.regexArgumentsValid())
+ return std::move(E);
+ return std::move(Filter);
+ }
+ /// Returns true if \p Remark satisfies all the provided filters.
+ bool filterRemark(const Remark &Remark);
+
+private:
+ /// Check if arguments can be parsed as valid regex types.
+ Error regexArgumentsValid();
+};
+
+/// Convert Regex string error to an error object.
+inline Error checkRegex(const Regex &Regex) {
+ std::string Error;
+ if (!Regex.isValid(Error))
+ return createStringError(make_error_code(std::errc::invalid_argument),
+ Twine("Regex: ", Error));
+ return Error::success();
+}
+
+/// Abstract counter class used to define the general required methods for
+/// counting a remark.
+struct Counter {
+ GroupBy Group = GroupBy::TOTAL;
+ Counter() = default;
+ Counter(enum GroupBy GroupBy) : Group(GroupBy) {}
+ /// Obtain the field for collecting remark info based on how we are
+ /// collecting. Remarks are grouped by FunctionName, Source, Source and
+ /// Function or collect by file.
+ std::optional<std::string> getGroupByKey(const Remark &Remark);
+
+ /// Collect count information from \p Remark organized based on \p Group
+ /// property.
+ virtual void collect(const Remark &) = 0;
+ /// Output the final count to the file \p OutputFileName
+ virtual Error print(StringRef OutputFileName) = 0;
+ virtual ~Counter() = default;
+};
+
+/// Count remarks based on the provided \p Keys argument and summing up the
+/// value for each matching key organized by source, function or reporting a
+/// total for the specified remark file.
+/// Reporting count grouped by source:
+///
+/// | source | key1 | key2 | key3 |
+/// |---------------|------|------|------|
+/// | path/to/file1 | 0 | 1 | 3 |
+/// | path/to/file2 | 1 | 0 | 2 |
+/// | path/to/file3 | 2 | 3 | 1 |
+///
+/// Reporting count grouped by function:
+///
+/// | Function | key1 | key2 | key3 |
+/// |---------------|------|------|------|
+/// | function1 | 0 | 1 | 3 |
+/// | function2 | 1 | 0 | 2 |
+/// | function3 | 2 | 3 | 1 |
+struct ArgumentCounter : Counter {
+ /// The internal object to keep the count for the remarks. The first argument
+ /// corresponds to the property we are collecting for this can be either a
+ /// source or function. The second argument is a row of integers where each
+ /// item in the row is the count for a specified key.
+ std::map<std::string, SmallVector<unsigned, 4>> CountByKeysMap;
+ /// A set of all the remark argument found in the remark file. The second
+ /// argument is the index of each of those arguments which can be used in
+ /// `CountByKeysMap` to fill count information for that argument.
+ MapVector<StringRef, unsigned> ArgumentSetIdxMap;
+ /// Create an argument counter. If the provided \p Arguments represent a regex
+ /// vector then we need to check that the provided regular expressions are
+ /// valid if not we return an Error.
+ static Expected<ArgumentCounter>
+ createArgumentCounter(GroupBy Group, ArrayRef<FilterMatcher> Arguments,
+ StringRef Buffer, Filters &Filter) {
+ ArgumentCounter AC;
+ AC.Group = Group;
+ for (auto &Arg : Arguments) {
+ if (Arg.IsRegex) {
+ if (auto E = checkRegex(Arg.FilterRE))
+ return std::move(E);
+ }
+ }
+ if (auto E = AC.getAllMatchingArgumentsInRemark(Buffer, Arguments, Filter))
+ return std::move(E);
+ return AC;
+ }
+
+ /// Update the internal count map based on the remark integer arguments that
+ /// correspond the the user specified argument keys to collect for.
+ void collect(const Remark &) override;
+
+ /// Print a CSV table consisting of an index which is specified by \p
+ /// `Group` and can be a function name, source file name or function name
+ /// with the full source path and columns of user specified remark arguments
+ /// to collect the count for.
+ Error print(StringRef OutputFileName) override;
+
+private:
+ /// collect all the arguments that match the list of \p Arguments provided by
+ /// parsing through \p Buffer of remarks and filling \p ArgumentSetIdxMap
+ /// acting as a row for for all the keys that we are interested in collecting
+ /// information for.
+ Error getAllMatchingArgumentsInRemark(StringRef Buffer,
+ ArrayRef<FilterMatcher> Arguments,
+ Filters &Filter);
+};
+
+/// Collect remarks based by counting the existance of individual remarks. The
+/// reported table will be structured based on the provided \p Group argument
+/// by reporting count for functions, source or total count for the provided
+/// remark file.
+struct RemarkCounter : Counter {
+ std::map<std::string, unsigned> CountedByRemarksMap;
+ RemarkCounter(GroupBy Group) : Counter(Group) {}
+
+ /// Advance the internal map count broken by \p Group when
+ /// seeing \p Remark.
+ void collect(const Remark &) override;
+
+ /// Print a CSV table consisting of an index which is specified by \p
+ /// `Group` and can be a function name, source file name or function name
+ /// with the full source path and a counts column corresponding to the count
+ /// of each individual remark at th index.
+ Error print(StringRef OutputFileName) override;
+};
+} // namespace remarks
+
+} // namespace llvm
+#endif // TOOLS_LLVM_REMARKCOUNTER_H
diff --git a/src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkSizeDiff.cpp
similarity index 86%
rename from src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp
rename to src/llvm-project/llvm/tools/llvm-remarkutil/RemarkSizeDiff.cpp
index d97589e..35ea432 100644
--- a/src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkSizeDiff.cpp
@@ -1,4 +1,4 @@
-//===-------------- llvm-remark-size-diff/RemarkSizeDiff.cpp --------------===//
+//===-------------- RemarkSizeDiff.cpp ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -14,51 +14,38 @@
///
//===----------------------------------------------------------------------===//
-#include "llvm-c/Remarks.h"
-#include "llvm/ADT/STLExtras.h"
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Remarks/Remark.h"
-#include "llvm/Remarks/RemarkParser.h"
-#include "llvm/Remarks/RemarkSerializer.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/JSON.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
using namespace llvm;
-
-enum ParserFormatOptions { yaml, bitstream };
+using namespace remarks;
+using namespace remarkutil;
+static cl::SubCommand
+ RemarkSizeDiffUtil("size-diff",
+ "Diff instruction count and stack size remarks "
+ "between two remark files");
enum ReportStyleOptions { human_output, json_output };
-static cl::OptionCategory SizeDiffCategory("llvm-remark-size-diff options");
static cl::opt<std::string> InputFileNameA(cl::Positional, cl::Required,
- cl::cat(SizeDiffCategory),
+ cl::sub(RemarkSizeDiffUtil),
cl::desc("remarks_a"));
static cl::opt<std::string> InputFileNameB(cl::Positional, cl::Required,
- cl::cat(SizeDiffCategory),
+ cl::sub(RemarkSizeDiffUtil),
cl::desc("remarks_b"));
static cl::opt<std::string> OutputFilename("o", cl::init("-"),
- cl::cat(SizeDiffCategory),
+ cl::sub(RemarkSizeDiffUtil),
cl::desc("Output"),
cl::value_desc("file"));
-static cl::opt<ParserFormatOptions>
- ParserFormat("parser", cl::cat(SizeDiffCategory), cl::init(bitstream),
- cl::desc("Set the remark parser format:"),
- cl::values(clEnumVal(yaml, "YAML format"),
- clEnumVal(bitstream, "Bitstream format")));
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(RemarkSizeDiffUtil)
static cl::opt<ReportStyleOptions> ReportStyle(
- "report_style", cl::cat(SizeDiffCategory),
+ "report_style", cl::sub(RemarkSizeDiffUtil),
cl::init(ReportStyleOptions::human_output),
cl::desc("Choose the report output format:"),
cl::values(clEnumValN(human_output, "human", "Human-readable format"),
clEnumValN(json_output, "json", "JSON format")));
-static cl::opt<bool> PrettyPrint("pretty", cl::cat(SizeDiffCategory),
+static cl::opt<bool> PrettyPrint("pretty", cl::sub(RemarkSizeDiffUtil),
cl::init(false),
cl::desc("Pretty-print JSON"));
@@ -300,14 +287,12 @@
static Error readFileAndProcessRemarks(
StringRef InputFileName,
StringMap<InstCountAndStackSize> &FuncNameToSizeInfo) {
- auto Buf = MemoryBuffer::getFile(InputFileName);
- if (auto EC = Buf.getError())
- return createStringError(
- EC, Twine("Cannot open file '" + InputFileName + "': " + EC.message()));
- auto MaybeParser = remarks::createRemarkParserFromMeta(
- ParserFormat == bitstream ? remarks::Format::Bitstream
- : remarks::Format::YAML,
- (*Buf)->getBuffer());
+
+ auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+ if (!MaybeBuf)
+ return MaybeBuf.takeError();
+ auto MaybeParser =
+ createRemarkParserFromMeta(InputFormat, (*MaybeBuf)->getBuffer());
if (!MaybeParser)
return MaybeParser.takeError();
auto &Parser = **MaybeParser;
@@ -340,17 +325,13 @@
///
/// \returns true if readFileAndProcessRemarks returned no errors. False
/// otherwise.
-static bool tryReadFileAndProcessRemarks(
+static Error tryReadFileAndProcessRemarks(
StringRef InputFileName,
StringMap<InstCountAndStackSize> &FuncNameToSizeInfo) {
if (Error E = readFileAndProcessRemarks(InputFileName, FuncNameToSizeInfo)) {
- handleAllErrors(std::move(E), [&](const ErrorInfoBase &PE) {
- PE.log(WithColor::error());
- errs() << '\n';
- });
- return false;
+ return E;
}
- return true;
+ return Error::success();
}
/// Populates \p FuncDiffs with the difference between \p
@@ -489,33 +470,32 @@
}
/// Boolean wrapper for outputDiff which handles errors.
-static bool
+static Error
tryOutputAllDiffs(StringRef InputFileNameA, StringRef InputFileNameB,
DiffsCategorizedByFilesPresent &DiffsByFilesPresent) {
if (Error E =
outputAllDiffs(InputFileNameA, InputFileNameB, DiffsByFilesPresent)) {
- handleAllErrors(std::move(E), [&](const ErrorInfoBase &PE) {
- PE.log(WithColor::error());
- errs() << '\n';
- });
- return false;
+ return E;
}
- return true;
+ return Error::success();
}
-int main(int argc, const char **argv) {
- InitLLVM X(argc, argv);
- cl::HideUnrelatedOptions(SizeDiffCategory);
- cl::ParseCommandLineOptions(argc, argv,
- "Diff instruction count and stack size remarks "
- "between two remark files.\n");
+static Error trySizeSiff() {
StringMap<InstCountAndStackSize> FuncNameToSizeInfoA;
StringMap<InstCountAndStackSize> FuncNameToSizeInfoB;
- if (!tryReadFileAndProcessRemarks(InputFileNameA, FuncNameToSizeInfoA) ||
- !tryReadFileAndProcessRemarks(InputFileNameB, FuncNameToSizeInfoB))
- return 1;
+ if (auto E =
+ tryReadFileAndProcessRemarks(InputFileNameA, FuncNameToSizeInfoA))
+ return E;
+ if (auto E =
+ tryReadFileAndProcessRemarks(InputFileNameB, FuncNameToSizeInfoB))
+ return E;
DiffsCategorizedByFilesPresent DiffsByFilesPresent;
computeDiff(FuncNameToSizeInfoA, FuncNameToSizeInfoB, DiffsByFilesPresent);
- if (!tryOutputAllDiffs(InputFileNameA, InputFileNameB, DiffsByFilesPresent))
- return 1;
+ if (auto E = tryOutputAllDiffs(InputFileNameA, InputFileNameB,
+ DiffsByFilesPresent))
+ return E;
+ return Error::success();
}
+
+static CommandRegistration RemarkSizeSiffRegister(&RemarkSizeDiffUtil,
+ trySizeSiff);
\ No newline at end of file
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
index 14af5d2..8ab3fbb 100644
--- a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
@@ -1,4 +1,4 @@
-//===--------- llvm-remarkutil/RemarkUtil.cpp -----------===//
+//===--------- llvm-remarkutil/RemarkUtil.cpp -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -8,370 +8,34 @@
/// Utility for remark files.
//===----------------------------------------------------------------------===//
-#include "llvm-c/Remarks.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Remarks/Remark.h"
-#include "llvm/Remarks/RemarkFormat.h"
-#include "llvm/Remarks/RemarkParser.h"
-#include "llvm/Remarks/YAMLRemarkSerializer.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
+#include "RemarkUtilRegistry.h"
#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
using namespace llvm;
-using namespace remarks;
+using namespace llvm::remarkutil;
+ExitOnError ExitOnErr;
-static ExitOnError ExitOnErr;
-static cl::OptionCategory RemarkUtilCategory("llvm-remarkutil options");
-namespace subopts {
-static cl::SubCommand
- YAML2Bitstream("yaml2bitstream",
- "Convert YAML remarks to bitstream remarks");
-static cl::SubCommand
- Bitstream2YAML("bitstream2yaml",
- "Convert bitstream remarks to YAML remarks");
-static cl::SubCommand InstructionCount(
- "instruction-count",
- "Function instruction count information (requires asm-printer remarks)");
-static cl::SubCommand
- AnnotationCount("annotation-count",
- "Collect count information from annotation remarks (uses "
- "AnnotationRemarksPass)");
-} // namespace subopts
-
-// Keep input + output help + names consistent across the various modes via a
-// hideous macro.
-#define INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SUBOPT) \
- static cl::opt<std::string> InputFileName( \
- cl::Positional, cl::cat(RemarkUtilCategory), cl::init("-"), \
- cl::desc("<input file>"), cl::sub(SUBOPT)); \
- static cl::opt<std::string> OutputFileName( \
- "o", cl::init("-"), cl::cat(RemarkUtilCategory), cl::desc("Output"), \
- cl::value_desc("filename"), cl::sub(SUBOPT));
-
-// Keep Input format and names consistent accross the modes via a macro.
-#define INPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT) \
- static cl::opt<Format> InputFormat( \
- "parser", cl::desc("Input remark format to parse"), \
- cl::values(clEnumValN(Format::YAML, "yaml", "YAML"), \
- clEnumValN(Format::Bitstream, "bitstream", "Bitstream")), \
- cl::sub(SUBOPT));
-
-#define DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(SUBOPT) \
- static cl::opt<bool> UseDebugLoc( \
- "use-debug-loc", \
- cl::desc( \
- "Add debug loc information when generating tables for " \
- "functions. The loc is represented as (path:line number:column " \
- "number)"), \
- cl::init(false), cl::sub(SUBOPT));
-namespace yaml2bitstream {
-/// Remark format to parse.
-static constexpr Format InputFormat = Format::YAML;
-/// Remark format to output.
-static constexpr Format OutputFormat = Format::Bitstream;
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::YAML2Bitstream)
-} // namespace yaml2bitstream
-
-namespace bitstream2yaml {
-/// Remark format to parse.
-static constexpr Format InputFormat = Format::Bitstream;
-/// Remark format to output.
-static constexpr Format OutputFormat = Format::YAML;
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::Bitstream2YAML)
-} // namespace bitstream2yaml
-
-namespace instructioncount {
-INPUT_FORMAT_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
-DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
-} // namespace instructioncount
-
-namespace annotationcount {
-INPUT_FORMAT_COMMAND_LINE_OPTIONS(subopts::AnnotationCount)
-static cl::opt<std::string> AnnotationTypeToCollect(
- "annotation-type", cl::desc("annotation-type remark to collect count for"),
- cl::sub(subopts::AnnotationCount));
-INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::AnnotationCount)
-DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(subopts::AnnotationCount)
-} // namespace annotationcount
-
-/// \returns A MemoryBuffer for the input file on success, and an Error
-/// otherwise.
-static Expected<std::unique_ptr<MemoryBuffer>>
-getInputMemoryBuffer(StringRef InputFileName) {
- auto MaybeBuf = MemoryBuffer::getFileOrSTDIN(InputFileName);
- if (auto ErrorCode = MaybeBuf.getError())
- return createStringError(ErrorCode,
- Twine("Cannot open file '" + InputFileName +
- "': " + ErrorCode.message()));
- return std::move(*MaybeBuf);
-}
-
-/// \returns A ToolOutputFile which can be used for outputting the results of
-/// some tool mode.
-/// \p OutputFileName is the desired destination.
-/// \p Flags controls whether or not the file is opened for writing in text
-/// mode, as a binary, etc. See sys::fs::OpenFlags for more detail.
-static Expected<std::unique_ptr<ToolOutputFile>>
-getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags) {
- if (OutputFileName == "")
- OutputFileName = "-";
- std::error_code ErrorCode;
- auto OF = std::make_unique<ToolOutputFile>(OutputFileName, ErrorCode, Flags);
- if (ErrorCode)
- return errorCodeToError(ErrorCode);
- return std::move(OF);
-}
-
-/// \returns A ToolOutputFile which can be used for writing remarks on success,
-/// and an Error otherwise.
-/// \p OutputFileName is the desired destination.
-/// \p OutputFormat
-static Expected<std::unique_ptr<ToolOutputFile>>
-getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat) {
- assert((OutputFormat == Format::YAML || OutputFormat == Format::Bitstream) &&
- "Expected one of YAML or Bitstream!");
- return getOutputFileWithFlags(OutputFileName, OutputFormat == Format::YAML
- ? sys::fs::OF_TextWithCRLF
- : sys::fs::OF_None);
-}
-
-static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) {
- return UseDebugLoc && !Remark.Loc.has_value();
-}
-
-namespace yaml2bitstream {
-/// Parses all remarks in the input YAML file.
-/// \p [out] ParsedRemarks - Filled with remarks parsed from the input file.
-/// \p [out] StrTab - A string table populated for later remark serialization.
-/// \returns Error::success() if all remarks were successfully parsed, and an
-/// Error otherwise.
-static Error
-tryParseRemarksFromYAMLFile(std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
- StringTable &StrTab) {
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- auto &Parser = **MaybeParser;
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next()) {
- StrTab.internalize(**MaybeRemark);
- ParsedRemarks.push_back(std::move(*MaybeRemark));
- }
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- return Error::success();
-}
-
-/// Reserialize a list of parsed YAML remarks into bitstream remarks.
-/// \p ParsedRemarks - A list of remarks.
-/// \p StrTab - The string table for the remarks.
-/// \returns Error::success() on success.
-static Error tryReserializeYAML2Bitstream(
- const std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
- StringTable &StrTab) {
- auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- auto MaybeSerializer = createRemarkSerializer(
- OutputFormat, SerializerMode::Standalone, OF->os(), std::move(StrTab));
- if (!MaybeSerializer)
- return MaybeSerializer.takeError();
- auto Serializer = std::move(*MaybeSerializer);
- for (const auto &Remark : ParsedRemarks)
- Serializer->emit(*Remark);
- OF->keep();
- return Error::success();
-}
-
-/// Parse YAML remarks and reserialize as bitstream remarks.
-/// \returns Error::success() on success, and an Error otherwise.
-static Error tryYAML2Bitstream() {
- StringTable StrTab;
- std::vector<std::unique_ptr<Remark>> ParsedRemarks;
- ExitOnErr(tryParseRemarksFromYAMLFile(ParsedRemarks, StrTab));
- return tryReserializeYAML2Bitstream(ParsedRemarks, StrTab);
-}
-} // namespace yaml2bitstream
-
-namespace bitstream2yaml {
-/// Parse bitstream remarks and reserialize as YAML remarks.
-/// \returns An Error if reserialization fails, or Error::success() on success.
-static Error tryBitstream2YAML() {
- // Create the serializer.
- auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- auto MaybeSerializer = createRemarkSerializer(
- OutputFormat, SerializerMode::Standalone, OF->os());
- if (!MaybeSerializer)
- return MaybeSerializer.takeError();
-
- // Create the parser.
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto Serializer = std::move(*MaybeSerializer);
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- auto &Parser = **MaybeParser;
-
- // Parse + reserialize all remarks.
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next())
- Serializer->emit(**MaybeRemark);
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- return Error::success();
-}
-} // namespace bitstream2yaml
-
-namespace instructioncount {
-/// Outputs all instruction count remarks in the file as a CSV.
-/// \returns Error::success() on success, and an Error otherwise.
-static Error tryInstructionCount() {
- // Create the output buffer.
- auto MaybeOF = getOutputFileWithFlags(OutputFileName,
- /*Flags = */ sys::fs::OF_TextWithCRLF);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- // Create a parser for the user-specified input format.
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- // Emit CSV header.
- if (UseDebugLoc)
- OF->os() << "Source,";
- OF->os() << "Function,InstructionCount\n";
- // Parse all remarks. Whenever we see an instruction count remark, output
- // the file name and the number of instructions.
- auto &Parser = **MaybeParser;
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next()) {
- auto &Remark = **MaybeRemark;
- if (Remark.RemarkName != "InstructionCount")
- continue;
- if (shouldSkipRemark(UseDebugLoc, Remark))
- continue;
- auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) {
- return Arg.Key == "NumInstructions";
- });
- assert(InstrCountArg != Remark.Args.end() &&
- "Expected instruction count remarks to have a NumInstructions key?");
- if (UseDebugLoc) {
- std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
- std::to_string(Remark.Loc->SourceLine) + +":" +
- std::to_string(Remark.Loc->SourceColumn);
- OF->os() << Loc << ",";
+static Error handleSubOptions() {
+ for (auto *SC : cl::getRegisteredSubcommands()) {
+ if (*SC) {
+ // If no subcommand was provided, we need to explicitly check if this is
+ // the top-level subcommand.
+ if (SC == &cl::SubCommand::getTopLevel())
+ break;
+ if (auto C = dispatch(SC)) {
+ return C();
+ }
}
- OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n";
}
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- OF->keep();
- return Error::success();
-}
-} // namespace instructioncount
-
-namespace annotationcount {
-static Error tryAnnotationCount() {
- // Create the output buffer.
- auto MaybeOF = getOutputFileWithFlags(OutputFileName,
- /*Flags = */ sys::fs::OF_TextWithCRLF);
- if (!MaybeOF)
- return MaybeOF.takeError();
- auto OF = std::move(*MaybeOF);
- // Create a parser for the user-specified input format.
- auto MaybeBuf = getInputMemoryBuffer(InputFileName);
- if (!MaybeBuf)
- return MaybeBuf.takeError();
- auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
- if (!MaybeParser)
- return MaybeParser.takeError();
- // Emit CSV header.
- if (UseDebugLoc)
- OF->os() << "Source,";
- OF->os() << "Function,Count\n";
- // Parse all remarks. When we see the specified remark collect the count
- // information.
- auto &Parser = **MaybeParser;
- auto MaybeRemark = Parser.next();
- for (; MaybeRemark; MaybeRemark = Parser.next()) {
- auto &Remark = **MaybeRemark;
- if (Remark.RemarkName != "AnnotationSummary")
- continue;
- if (shouldSkipRemark(UseDebugLoc, Remark))
- continue;
- auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) {
- return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect;
- });
- if (RemarkNameArg == Remark.Args.end())
- continue;
- auto *CountArg = find_if(
- Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; });
- assert(CountArg != Remark.Args.end() &&
- "Expected annotation-type remark to have a count key?");
- if (UseDebugLoc) {
- std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
- std::to_string(Remark.Loc->SourceLine) + +":" +
- std::to_string(Remark.Loc->SourceColumn);
- OF->os() << Loc << ",";
- }
- OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n";
- }
- auto E = MaybeRemark.takeError();
- if (!E.isA<EndOfFileError>())
- return E;
- consumeError(std::move(E));
- OF->keep();
- return Error::success();
-}
-
-} // namespace annotationcount
-/// Handle user-specified suboptions (e.g. yaml2bitstream, bitstream2yaml).
-/// \returns An Error if the specified suboption fails or if no suboption was
-/// specified. Otherwise, Error::success().
-static Error handleSuboptions() {
- if (subopts::Bitstream2YAML)
- return bitstream2yaml::tryBitstream2YAML();
- if (subopts::YAML2Bitstream)
- return yaml2bitstream::tryYAML2Bitstream();
- if (subopts::InstructionCount)
- return instructioncount::tryInstructionCount();
- if (subopts::AnnotationCount)
- return annotationcount::tryAnnotationCount();
return make_error<StringError>(
"Please specify a subcommand. (See -help for options)",
inconvertibleErrorCode());
}
-int main(int argc, const char **argv) {
+int main(int argc, char *argv[]) {
InitLLVM X(argc, argv);
- cl::HideUnrelatedOptions(RemarkUtilCategory);
cl::ParseCommandLineOptions(argc, argv, "Remark file utilities\n");
ExitOnErr.setBanner(std::string(argv[0]) + ": error: ");
- ExitOnErr(handleSuboptions());
+ ExitOnErr(handleSubOptions());
}
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
new file mode 100644
index 0000000..c035716
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
@@ -0,0 +1,57 @@
+//===- RemarkUtilHelpers.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers for remark utilites
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkUtilHelpers.h"
+
+namespace llvm {
+namespace remarks {
+/// \returns A MemoryBuffer for the input file on success, and an Error
+/// otherwise.
+Expected<std::unique_ptr<MemoryBuffer>>
+getInputMemoryBuffer(StringRef InputFileName) {
+ auto MaybeBuf = MemoryBuffer::getFileOrSTDIN(InputFileName);
+ if (auto ErrorCode = MaybeBuf.getError())
+ return createStringError(ErrorCode,
+ Twine("Cannot open file '" + InputFileName +
+ "': " + ErrorCode.message()));
+ return std::move(*MaybeBuf);
+}
+
+/// \returns A ToolOutputFile which can be used for outputting the results of
+/// some tool mode.
+/// \p OutputFileName is the desired destination.
+/// \p Flags controls whether or not the file is opened for writing in text
+/// mode, as a binary, etc. See sys::fs::OpenFlags for more detail.
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags) {
+ if (OutputFileName == "")
+ OutputFileName = "-";
+ std::error_code ErrorCode;
+ auto OF = std::make_unique<ToolOutputFile>(OutputFileName, ErrorCode, Flags);
+ if (ErrorCode)
+ return errorCodeToError(ErrorCode);
+ return std::move(OF);
+}
+
+/// \returns A ToolOutputFile which can be used for writing remarks on success,
+/// and an Error otherwise.
+/// \p OutputFileName is the desired destination.
+/// \p OutputFormat
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat) {
+ assert((OutputFormat == Format::YAML || OutputFormat == Format::Bitstream) &&
+ "Expected one of YAML or Bitstream!");
+ return getOutputFileWithFlags(OutputFileName, OutputFormat == Format::YAML
+ ? sys::fs::OF_TextWithCRLF
+ : sys::fs::OF_None);
+}
+} // namespace remarks
+} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
new file mode 100644
index 0000000..5d23352
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
@@ -0,0 +1,59 @@
+//===- RemarkUtilHelpers.h ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers for remark utilites
+//
+//===----------------------------------------------------------------------===//
+#include "llvm-c/Remarks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Remarks/Remark.h"
+#include "llvm/Remarks/RemarkFormat.h"
+#include "llvm/Remarks/RemarkParser.h"
+#include "llvm/Remarks/YAMLRemarkSerializer.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+// Keep input + output help + names consistent across the various modes via a
+// hideous macro.
+#define INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SUBOPT) \
+ static cl::opt<std::string> InputFileName(cl::Positional, cl::init("-"), \
+ cl::desc("<input file>"), \
+ cl::sub(SUBOPT)); \
+ static cl::opt<std::string> OutputFileName( \
+ "o", cl::init("-"), cl::desc("Output"), cl::value_desc("filename"), \
+ cl::sub(SUBOPT));
+
+// Keep Input format and names consistent accross the modes via a macro.
+#define INPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT) \
+ static cl::opt<Format> InputFormat( \
+ "parser", cl::desc("Input remark format to parse"), \
+ cl::values(clEnumValN(Format::YAML, "yaml", "YAML"), \
+ clEnumValN(Format::Bitstream, "bitstream", "Bitstream")), \
+ cl::sub(SUBOPT));
+
+#define DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(SUBOPT) \
+ static cl::opt<bool> UseDebugLoc( \
+ "use-debug-loc", \
+ cl::desc( \
+ "Add debug loc information when generating tables for " \
+ "functions. The loc is represented as (path:line number:column " \
+ "number)"), \
+ cl::init(false), cl::sub(SUBOPT));
+
+namespace llvm {
+namespace remarks {
+Expected<std::unique_ptr<MemoryBuffer>>
+getInputMemoryBuffer(StringRef InputFileName);
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags);
+Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat);
+} // namespace remarks
+} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
new file mode 100644
index 0000000..244a16d
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
@@ -0,0 +1,41 @@
+//===- RemarkUtilRegistry.cpp: Implement a command registry. --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement a simple subcommand registry.
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkUtilRegistry.h"
+#include <unordered_map>
+
+namespace llvm {
+namespace remarkutil {
+
+using HandlerType = std::function<Error()>;
+
+static std::unordered_map<cl::SubCommand *, HandlerType> &getCommands() {
+ static std::unordered_map<cl::SubCommand *, HandlerType> Commands;
+ return Commands;
+}
+
+CommandRegistration::CommandRegistration(cl::SubCommand *SC,
+ HandlerType Command) {
+ assert(getCommands().count(SC) == 0 &&
+ "Attempting to overwrite a command handler");
+ assert(Command && "Attempting to register an empty std::function<Error()>");
+ getCommands()[SC] = Command;
+}
+
+HandlerType dispatch(cl::SubCommand *SC) {
+ auto It = getCommands().find(SC);
+ assert(It != getCommands().end() &&
+ "Attempting to dispatch on un-registered SubCommand.");
+ return It->second;
+}
+
+} // namespace remarkutil
+} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h
new file mode 100644
index 0000000..2dd3a53
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.h
@@ -0,0 +1,40 @@
+//===- RemarkUtilRegistry.h: Implement a command registry. ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement a simple subcommand registry.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TOOLS_LLVM_REMARKUTIL_REGISTRY_H
+#define TOOLS_LLVM_REMARKUTIL_REGISTRY_H
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace remarkutil {
+
+// Use |CommandRegistration| as a global initialiser that registers a function
+// and associates it with |SC|. This requires that a command has not been
+// registered to a given |SC|.
+//
+// Usage:
+//
+// // At namespace scope.
+// static CommandRegistration Unused(&MySubCommand, [] { ... });
+//
+struct CommandRegistration {
+ CommandRegistration(cl::SubCommand *SC, std::function<Error()> Command);
+};
+
+// Requires that |SC| is not null and has an associated function to it.
+std::function<Error()> dispatch(cl::SubCommand *SC);
+
+} // namespace remarkutil
+} // namespace llvm
+
+#endif // TOOLS_LLVM_REMARKUTIL_REGISTRY_H
diff --git a/src/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/src/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
index df82fb0..4cb76f4 100644
--- a/src/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -892,6 +892,8 @@
StringRef SecContent = Dyld.getSectionContent(SectionID);
uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data());
SymInfo.setContent(ArrayRef<char>(CSymAddr, SymSize));
+ SymInfo.setTargetFlags(
+ Dyld.getSymbol(Symbol).getFlags().getTargetFlags());
}
}
return SymInfo;
@@ -924,7 +926,8 @@
};
auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer,
- StringRef SymbolName)
+ StringRef SymbolName,
+ StringRef KindNameFilter)
-> Expected<RuntimeDyldChecker::MemoryRegionInfo> {
if (!StubMap.count(StubContainer))
return make_error<StringError>("Stub container not found: " +
@@ -945,6 +948,11 @@
return StubMemInfo;
};
+ auto GetGOTInfo = [&GetStubInfo](StringRef StubContainer,
+ StringRef SymbolName) {
+ return GetStubInfo(StubContainer, SymbolName, "");
+ };
+
// We will initialize this below once we have the first object file and can
// know the endianness.
std::unique_ptr<RuntimeDyldChecker> Checker;
@@ -975,9 +983,10 @@
if (!Checker)
Checker = std::make_unique<RuntimeDyldChecker>(
- IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo,
- GetStubInfo, Obj.isLittleEndian() ? support::little : support::big,
- Disassembler.get(), InstPrinter.get(), dbgs());
+ IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
+ Obj.isLittleEndian() ? llvm::endianness::little
+ : llvm::endianness::big,
+ TheTriple, MCPU, SubtargetFeatures(), dbgs());
auto FileName = sys::path::filename(InputFile);
MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);
diff --git a/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt
index 8ace190..b20ac31 100644
--- a/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -14,6 +14,9 @@
if(MSVC)
message(FATAL_ERROR "Generating libLLVM is not supported on MSVC")
endif()
+ if(ZOS)
+ message(FATAL_ERROR "Generating libLLVM is not supported on z/OS")
+ endif()
llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS})
@@ -30,19 +33,18 @@
if (LLVM_LINK_LLVM_DYLIB)
set(INSTALL_WITH_TOOLCHAIN INSTALL_WITH_TOOLCHAIN)
endif()
- add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB SONAME ${INSTALL_WITH_TOOLCHAIN} ${SOURCES})
+ if (WIN32)
+ add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB SONAME ${INSTALL_WITH_TOOLCHAIN} ${SOURCES})
+ else()
+ add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB OUTPUT_NAME LLVM ${INSTALL_WITH_TOOLCHAIN} ${SOURCES})
+ # Add symlink for backwards compatibility with old library name
+ llvm_install_library_symlink(LLVM-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX} $<TARGET_FILE_NAME:LLVM> SHARED FULL_DEST COMPONENT LLVM)
+ endif()
list(REMOVE_DUPLICATES LIB_NAMES)
- if((MINGW) OR (HAIKU)
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "NetBSD")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "DragonFly")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
- OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")) # FIXME: It should be "GNU ld for elf"
+ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+ set(LIB_NAMES -Wl,-all_load ${LIB_NAMES})
+ else()
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/simple_version_script.map.in
${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map)
@@ -53,15 +55,13 @@
# Solaris ld does not accept global: *; so there is no way to version *all* global symbols
set(LIB_NAMES -Wl,--version-script,${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map ${LIB_NAMES})
endif()
- if (NOT MINGW)
+ if (NOT MINGW AND NOT LLVM_LINKER_IS_SOLARISLD_ILLUMOS)
# Optimize function calls for default visibility definitions to avoid PLT and
# reduce dynamic relocations.
# Note: for -fno-pic default, the address of a function may be different from
# inside and outside libLLVM.so.
target_link_options(LLVM PRIVATE LINKER:-Bsymbolic-functions)
endif()
- elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
- set(LIB_NAMES -Wl,-all_load ${LIB_NAMES})
endif()
target_link_libraries(LLVM PRIVATE ${LIB_NAMES})
diff --git a/src/llvm-project/llvm/tools/llvm-size/llvm-size.cpp b/src/llvm-project/llvm/tools/llvm-size/llvm-size.cpp
index 048a98b..78b207e 100644
--- a/src/llvm-project/llvm/tools/llvm-size/llvm-size.cpp
+++ b/src/llvm-project/llvm/tools/llvm-size/llvm-size.cpp
@@ -25,7 +25,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/WithColor.h"
@@ -41,9 +40,7 @@
using namespace llvm::opt; // for HelpHidden in Opts.inc
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -56,13 +53,7 @@
#undef PREFIX
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -871,7 +862,6 @@
}
int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) {
- InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
SizeOptTable Tbl;
diff --git a/src/llvm-project/llvm/tools/llvm-special-case-list-fuzzer/special-case-list-fuzzer.cpp b/src/llvm-project/llvm/tools/llvm-special-case-list-fuzzer/special-case-list-fuzzer.cpp
index aaab5f8..0691f29 100644
--- a/src/llvm-project/llvm/tools/llvm-special-case-list-fuzzer/special-case-list-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-special-case-list-fuzzer/special-case-list-fuzzer.cpp
@@ -12,8 +12,9 @@
#include <cstdlib>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- std::unique_ptr<llvm::MemoryBuffer> Buf = llvm::MemoryBuffer::getMemBuffer(
- llvm::StringRef(reinterpret_cast<const char *>(Data), Size), "", false);
+ std::string Payload(reinterpret_cast<const char *>(Data), Size);
+ std::unique_ptr<llvm::MemoryBuffer> Buf =
+ llvm::MemoryBuffer::getMemBuffer(Payload);
if (!Buf)
return 0;
diff --git a/src/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp b/src/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp
index d1cf160..8cb7fce 100644
--- a/src/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp
+++ b/src/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp
@@ -132,9 +132,9 @@
// Define a few arguments
LLVMContext &Context = M->getContext();
Type* ArgsTy[] = {
- Type::getInt8PtrTy(Context),
- Type::getInt32PtrTy(Context),
- Type::getInt64PtrTy(Context),
+ PointerType::get(Context, 0),
+ PointerType::get(Context, 0),
+ PointerType::get(Context, 0),
Type::getInt32Ty(Context),
Type::getInt64Ty(Context),
Type::getInt8Ty(Context)
@@ -175,7 +175,7 @@
Ty = Type::getPPC_FP128Ty(Context);
else if (Arg == "x86_mmx")
Ty = Type::getX86_MMXTy(Context);
- else if (Arg.startswith("i")) {
+ else if (Arg.starts_with("i")) {
unsigned N = 0;
Arg.drop_front().getAsInteger(10, N);
if (N > 0)
diff --git a/src/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp b/src/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp
index d9bc34e..8642be3 100644
--- a/src/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp
+++ b/src/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp
@@ -33,9 +33,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -47,14 +45,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
diff --git a/src/llvm-project/llvm/tools/llvm-symbolizer/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-symbolizer/CMakeLists.txt
index a6bc047..6f8de1f 100644
--- a/src/llvm-project/llvm/tools/llvm-symbolizer/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-symbolizer/CMakeLists.txt
@@ -20,9 +20,12 @@
DEPENDS
SymbolizerOptsTableGen
+ GENERATE_DRIVER
)
-target_link_libraries(llvm-symbolizer PRIVATE LLVMDebuginfod)
+if(NOT LLVM_TOOL_LLVM_DRIVER_BUILD)
+ target_link_libraries(llvm-symbolizer PRIVATE LLVMDebuginfod)
+endif()
add_llvm_tool_symlink(llvm-addr2line llvm-symbolizer)
diff --git a/src/llvm-project/llvm/tools/llvm-symbolizer/Opts.td b/src/llvm-project/llvm/tools/llvm-symbolizer/Opts.td
index 6742e08..edc80bf 100644
--- a/src/llvm-project/llvm/tools/llvm-symbolizer/Opts.td
+++ b/src/llvm-project/llvm/tools/llvm-symbolizer/Opts.td
@@ -82,5 +82,3 @@
// Compatibility aliases for pprof's symbolizer.
def : Flag<["-"], "demangle=true">, Alias<demangle>, HelpText<"Alias for --demangle">;
def : Flag<["-"], "demangle=false">, Alias<no_demangle>, HelpText<"Alias for --no-demangle">;
-// Compatibility no-op options.
-def : Flag<["--"], "use-symbol-table=true">;
diff --git a/src/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/src/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 3e342a4..b98bdbc 100644
--- a/src/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -32,8 +32,9 @@
#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/WithColor.h"
@@ -50,9 +51,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -64,14 +63,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -86,10 +80,10 @@
static std::string ToolName;
-static void printError(const ErrorInfoBase &EI, StringRef Path) {
+static void printError(const ErrorInfoBase &EI, StringRef AuxInfo) {
WithColor::error(errs(), ToolName);
- if (!EI.isA<FileError>())
- errs() << "'" << Path << "': ";
+ if (!AuxInfo.empty())
+ errs() << "'" << AuxInfo << "': ";
EI.log(errs());
errs() << '\n';
}
@@ -135,12 +129,37 @@
HTTPClient::initialize();
}
-static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
- StringRef InputString, Command &Cmd,
- std::string &ModuleName, object::BuildID &BuildID,
- uint64_t &ModuleOffset) {
+static StringRef getSpaceDelimitedWord(StringRef &Source) {
const char kDelimiters[] = " \n\r";
- ModuleName = "";
+ const char *Pos = Source.data();
+ StringRef Result;
+ Pos += strspn(Pos, kDelimiters);
+ if (*Pos == '"' || *Pos == '\'') {
+ char Quote = *Pos;
+ Pos++;
+ const char *End = strchr(Pos, Quote);
+ if (!End)
+ return StringRef();
+ Result = StringRef(Pos, End - Pos);
+ Pos = End + 1;
+ } else {
+ int NameLength = strcspn(Pos, kDelimiters);
+ Result = StringRef(Pos, NameLength);
+ Pos += NameLength;
+ }
+ Source = StringRef(Pos, Source.end() - Pos);
+ return Result;
+}
+
+static Error makeStringError(StringRef Msg) {
+ return make_error<StringError>(Msg, inconvertibleErrorCode());
+}
+
+static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
+ StringRef InputString, Command &Cmd,
+ std::string &ModuleName, object::BuildID &BuildID,
+ StringRef &Symbol, uint64_t &Offset) {
+ ModuleName = BinaryName;
if (InputString.consume_front("CODE ")) {
Cmd = Command::Code;
} else if (InputString.consume_front("DATA ")) {
@@ -152,74 +171,119 @@
Cmd = Command::Code;
}
- const char *Pos;
- // Skip delimiters and parse input filename (if needed).
- if (BinaryName.empty() && BuildID.empty()) {
- bool HasFilePrefix = false;
- bool HasBuildIDPrefix = false;
- while (true) {
- if (InputString.consume_front("FILE:")) {
- if (HasFilePrefix)
- return false;
- HasFilePrefix = true;
- continue;
- }
- if (InputString.consume_front("BUILDID:")) {
- if (HasBuildIDPrefix)
- return false;
- HasBuildIDPrefix = true;
- continue;
- }
- break;
+ // Parse optional input file specification.
+ bool HasFilePrefix = false;
+ bool HasBuildIDPrefix = false;
+ while (!InputString.empty()) {
+ InputString = InputString.ltrim();
+ if (InputString.consume_front("FILE:")) {
+ if (HasFilePrefix || HasBuildIDPrefix)
+ return makeStringError("duplicate input file specification prefix");
+ HasFilePrefix = true;
+ continue;
}
- if (HasFilePrefix && HasBuildIDPrefix)
- return false;
-
- Pos = InputString.data();
- Pos += strspn(Pos, kDelimiters);
- if (*Pos == '"' || *Pos == '\'') {
- char Quote = *Pos;
- Pos++;
- const char *End = strchr(Pos, Quote);
- if (!End)
- return false;
- ModuleName = std::string(Pos, End - Pos);
- Pos = End + 1;
- } else {
- int NameLength = strcspn(Pos, kDelimiters);
- ModuleName = std::string(Pos, NameLength);
- Pos += NameLength;
+ if (InputString.consume_front("BUILDID:")) {
+ if (HasBuildIDPrefix || HasFilePrefix)
+ return makeStringError("duplicate input file specification prefix");
+ HasBuildIDPrefix = true;
+ continue;
}
- if (HasBuildIDPrefix) {
- BuildID = parseBuildID(ModuleName);
- if (BuildID.empty())
- return false;
- ModuleName.clear();
- }
- } else {
- Pos = InputString.data();
- ModuleName = BinaryName.str();
+ break;
}
- // Skip delimiters and parse module offset.
- Pos += strspn(Pos, kDelimiters);
- int OffsetLength = strcspn(Pos, kDelimiters);
- StringRef Offset(Pos, OffsetLength);
- // GNU addr2line assumes the offset is hexadecimal and allows a redundant
+
+ // If an input file is not specified on the command line, try to extract it
+ // from the command.
+ if (HasBuildIDPrefix || HasFilePrefix) {
+ InputString = InputString.ltrim();
+ if (InputString.empty()) {
+ if (HasFilePrefix)
+ return makeStringError("must be followed by an input file");
+ else
+ return makeStringError("must be followed by a hash");
+ }
+
+ if (!BinaryName.empty() || !BuildID.empty())
+ return makeStringError("input file has already been specified");
+
+ StringRef Name = getSpaceDelimitedWord(InputString);
+ if (Name.empty())
+ return makeStringError("unbalanced quotes in input file name");
+ if (HasBuildIDPrefix) {
+ BuildID = parseBuildID(Name);
+ if (BuildID.empty())
+ return makeStringError("wrong format of build-id");
+ } else {
+ ModuleName = Name;
+ }
+ } else if (BinaryName.empty() && BuildID.empty()) {
+ // No input file has been specified. If the input string contains at least
+ // two items, assume that the first item is a file name.
+ ModuleName = getSpaceDelimitedWord(InputString);
+ if (ModuleName.empty())
+ return makeStringError("no input filename has been specified");
+ }
+
+ // Parse address specification, which can be an offset in module or a
+ // symbol with optional offset.
+ InputString = InputString.trim();
+ if (InputString.empty())
+ return makeStringError("no module offset has been specified");
+
+ // If input string contains a space, ignore everything after it. This behavior
+ // is consistent with GNU addr2line.
+ int AddrSpecLength = InputString.find_first_of(" \n\r");
+ StringRef AddrSpec = InputString.substr(0, AddrSpecLength);
+ bool StartsWithDigit = std::isdigit(AddrSpec.front());
+
+ // GNU addr2line assumes the address is hexadecimal and allows a redundant
// "0x" or "0X" prefix; do the same for compatibility.
if (IsAddr2Line)
- Offset.consume_front("0x") || Offset.consume_front("0X");
- return !Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset);
+ AddrSpec.consume_front("0x") || AddrSpec.consume_front("0X");
+
+ // If address specification is a number, treat it as a module offset.
+ if (!AddrSpec.getAsInteger(IsAddr2Line ? 16 : 0, Offset)) {
+ // Module offset is an address.
+ Symbol = StringRef();
+ return Error::success();
+ }
+
+ // If address specification starts with a digit, but is not a number, consider
+ // it as invalid.
+ if (StartsWithDigit || AddrSpec.empty())
+ return makeStringError("expected a number as module offset");
+
+ // Otherwise it is a symbol name, potentially with an offset.
+ Symbol = AddrSpec;
+ Offset = 0;
+
+ // If the address specification contains '+', try treating it as
+ // "symbol + offset".
+ size_t Plus = AddrSpec.rfind('+');
+ if (Plus != StringRef::npos) {
+ StringRef SymbolStr = AddrSpec.take_front(Plus);
+ StringRef OffsetStr = AddrSpec.substr(Plus + 1);
+ if (!SymbolStr.empty() && !OffsetStr.empty() &&
+ !OffsetStr.getAsInteger(0, Offset)) {
+ Symbol = SymbolStr;
+ return Error::success();
+ }
+ // The found '+' is not an offset delimiter.
+ }
+
+ return Error::success();
}
template <typename T>
void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd,
- uint64_t Offset, uint64_t AdjustVMA, bool ShouldInline,
- OutputStyle Style, LLVMSymbolizer &Symbolizer,
- DIPrinter &Printer) {
+ StringRef Symbol, uint64_t Offset, uint64_t AdjustVMA,
+ bool ShouldInline, OutputStyle Style,
+ LLVMSymbolizer &Symbolizer, DIPrinter &Printer) {
uint64_t AdjustedOffset = Offset - AdjustVMA;
object::SectionedAddress Address = {AdjustedOffset,
object::SectionedAddress::UndefSection};
- Request SymRequest = {ModuleName, Offset};
+ Request SymRequest = {
+ ModuleName, Symbol.empty() ? std::make_optional(Offset) : std::nullopt,
+ Symbol};
if (Cmd == Command::Data) {
Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(ModuleSpec, Address);
print(SymRequest, ResOrErr, Printer);
@@ -227,6 +291,10 @@
Expected<std::vector<DILocal>> ResOrErr =
Symbolizer.symbolizeFrame(ModuleSpec, Address);
print(SymRequest, ResOrErr, Printer);
+ } else if (!Symbol.empty()) {
+ Expected<std::vector<DILineInfo>> ResOrErr =
+ Symbolizer.findSymbol(ModuleSpec, Symbol, Offset);
+ print(SymRequest, ResOrErr, Printer);
} else if (ShouldInline) {
Expected<DIInliningInfo> ResOrErr =
Symbolizer.symbolizeInlinedCode(ModuleSpec, Address);
@@ -254,6 +322,11 @@
Symbolizer.pruneCache();
}
+static void printUnknownLineInfo(std::string ModuleName, DIPrinter &Printer) {
+ Request SymRequest = {ModuleName, std::nullopt, StringRef()};
+ Printer.print(SymRequest, DILineInfo());
+}
+
static void symbolizeInput(const opt::InputArgList &Args,
object::BuildIDRef IncomingBuildID,
uint64_t AdjustVMA, bool IsAddr2Line,
@@ -263,9 +336,14 @@
std::string ModuleName;
object::BuildID BuildID(IncomingBuildID.begin(), IncomingBuildID.end());
uint64_t Offset = 0;
- if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
- StringRef(InputString), Cmd, ModuleName, BuildID, Offset)) {
- Printer.printInvalidCommand({ModuleName, std::nullopt}, InputString);
+ StringRef Symbol;
+ if (Error E = parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
+ StringRef(InputString), Cmd, ModuleName, BuildID,
+ Symbol, Offset)) {
+ handleAllErrors(std::move(E), [&](const StringError &EI) {
+ printError(EI, InputString);
+ printUnknownLineInfo(ModuleName, Printer);
+ });
return;
}
bool ShouldInline = Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line);
@@ -274,11 +352,11 @@
if (!Args.hasArg(OPT_no_debuginfod))
enableDebuginfod(Symbolizer, Args);
std::string BuildIDStr = toHex(BuildID);
- executeCommand(BuildIDStr, BuildID, Cmd, Offset, AdjustVMA, ShouldInline,
- Style, Symbolizer, Printer);
+ executeCommand(BuildIDStr, BuildID, Cmd, Symbol, Offset, AdjustVMA,
+ ShouldInline, Style, Symbolizer, Printer);
} else {
- executeCommand(ModuleName, ModuleName, Cmd, Offset, AdjustVMA, ShouldInline,
- Style, Symbolizer, Printer);
+ executeCommand(ModuleName, ModuleName, Cmd, Symbol, Offset, AdjustVMA,
+ ShouldInline, Style, Symbolizer, Printer);
}
}
@@ -377,15 +455,12 @@
std::string InputString;
while (std::getline(std::cin, InputString)) {
InputString += '\n';
- Filter.filter(InputString);
+ Filter.filter(std::move(InputString));
}
Filter.finish();
}
-ExitOnError ExitOnErr;
-
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
+int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
sys::InitializeCOMRAII COM(sys::COMThreadingMode::MultiThreaded);
ToolName = argv[0];
@@ -484,7 +559,7 @@
if (auto *Arg = Args.getLastArg(OPT_obj_EQ); Arg) {
auto Status = Symbolizer.getOrCreateModuleInfo(Arg->getValue());
if (!Status) {
- Request SymRequest = {Arg->getValue(), 0};
+ Request SymRequest = {Arg->getValue(), 0, StringRef()};
handleAllErrors(Status.takeError(), [&](const ErrorInfoBase &EI) {
Printer->printError(SymRequest, EI);
});
diff --git a/src/llvm-project/llvm/tools/llvm-tapi-diff/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-tapi-diff/CMakeLists.txt
deleted file mode 100644
index 2870221..0000000
--- a/src/llvm-project/llvm/tools/llvm-tapi-diff/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-set(LLVM_LINK_COMPONENTS
- Object
- Support
- TextAPI
- )
-
-add_llvm_tool(llvm-tapi-diff
- llvm-tapi-diff.cpp
- DiffEngine.cpp
- )
diff --git a/src/llvm-project/llvm/tools/llvm-tapi-diff/llvm-tapi-diff.cpp b/src/llvm-project/llvm/tools/llvm-tapi-diff/llvm-tapi-diff.cpp
deleted file mode 100644
index 09dd6f7..0000000
--- a/src/llvm-project/llvm/tools/llvm-tapi-diff/llvm-tapi-diff.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-//===-- llvm-tapi-diff.cpp - tbd comparator command-line driver --*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the command-line driver for the llvm-tapi difference
-// engine.
-//
-//===----------------------------------------------------------------------===//
-#include "DiffEngine.h"
-#include "llvm/Object/TapiUniversal.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstdlib>
-
-using namespace llvm;
-using namespace MachO;
-using namespace object;
-
-namespace {
-cl::OptionCategory NMCat("llvm-tapi-diff Options");
-cl::opt<std::string> InputFileNameLHS(cl::Positional, cl::desc("<first file>"),
- cl::cat(NMCat));
-cl::opt<std::string> InputFileNameRHS(cl::Positional, cl::desc("<second file>"),
- cl::cat(NMCat));
-} // anonymous namespace
-
-Expected<std::unique_ptr<Binary>> convertFileToBinary(std::string &Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
- MemoryBuffer::getFileOrSTDIN(Filename);
- if (BufferOrErr.getError())
- return errorCodeToError(BufferOrErr.getError());
- return createBinary(BufferOrErr.get()->getMemBufferRef());
-}
-
-int main(int Argc, char **Argv) {
- InitLLVM X(Argc, Argv);
- cl::HideUnrelatedOptions(NMCat);
- cl::ParseCommandLineOptions(Argc, Argv, "Text-based Stubs Comparison Tool");
- if (InputFileNameLHS.empty() || InputFileNameRHS.empty()) {
- cl::PrintHelpMessage();
- return EXIT_FAILURE;
- }
-
- ExitOnError ExitOnErr("error: '" + InputFileNameLHS + "' ",
- /*DefaultErrorExitCode=*/2);
- auto BinLHS = ExitOnErr(convertFileToBinary(InputFileNameLHS));
-
- TapiUniversal *FileLHS = dyn_cast<TapiUniversal>(BinLHS.get());
- if (!FileLHS) {
- ExitOnErr(createStringError(std::errc::executable_format_error,
- "unsupported file format"));
- }
-
- ExitOnErr.setBanner("error: '" + InputFileNameRHS + "' ");
- auto BinRHS = ExitOnErr(convertFileToBinary(InputFileNameRHS));
-
- TapiUniversal *FileRHS = dyn_cast<TapiUniversal>(BinRHS.get());
- if (!FileRHS) {
- ExitOnErr(createStringError(std::errc::executable_format_error,
- "unsupported file format"));
- }
-
- raw_ostream &OS = outs();
-
- return DiffEngine(FileLHS, FileRHS).compareFiles(OS);
-}
diff --git a/src/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp b/src/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
index 9cc18f8..a091e37 100644
--- a/src/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
+++ b/src/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
@@ -28,9 +28,7 @@
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
@@ -42,14 +40,9 @@
#include "Opts.inc"
#undef PREFIX
+using namespace llvm::opt;
static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "Opts.inc"
#undef OPTION
};
diff --git a/src/llvm-project/llvm/tools/llvm-undname/llvm-undname.cpp b/src/llvm-project/llvm/tools/llvm-undname/llvm-undname.cpp
index 96f031a..d2d76de 100644
--- a/src/llvm-project/llvm/tools/llvm-undname/llvm-undname.cpp
+++ b/src/llvm-project/llvm/tools/llvm-undname/llvm-undname.cpp
@@ -116,7 +116,7 @@
StringRef Line(LineStr);
Line = Line.trim();
- if (Line.empty() || Line.startswith("#") || Line.startswith(";"))
+ if (Line.empty() || Line.starts_with("#") || Line.starts_with(";"))
continue;
// If the user is manually typing in these decorated names, don't echo
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-account.h b/src/llvm-project/llvm/tools/llvm-xray/xray-account.h
index 38d3ec9..0f24f93 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-account.h
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-account.h
@@ -13,9 +13,7 @@
#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
#define LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
-#include <map>
#include <utility>
-#include <vector>
#include "func-id-helper.h"
#include "llvm/ADT/Bitfields.h"
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp
index 82d0261..34832eb 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp
@@ -104,7 +104,7 @@
void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
// First write out the file header, in the correct endian-appropriate format
// (XRay assumes currently little endian).
- support::endian::Writer Writer(OS, support::endianness::little);
+ support::endian::Writer Writer(OS, llvm::endianness::little);
const auto &FH = Records.getFileHeader();
Writer.write(FH.Version);
Writer.write(FH.Type);
@@ -190,7 +190,7 @@
SmallVector<StackTrieNode *, 4> Siblings{};
if (parent == nullptr) {
- for (auto map_iter : StackRootsByThreadId) {
+ for (const auto &map_iter : StackRootsByThreadId) {
// Only look for siblings in other threads.
if (map_iter.first != TId)
for (auto node_iter : map_iter.second) {
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp
index 295f7a7..017ff03 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp
@@ -101,7 +101,7 @@
// Then we validate while printing each block.
BlockVerifier BV;
- for (auto ProcessThreadBlocks : Index) {
+ for (const auto &ProcessThreadBlocks : Index) {
auto &Blocks = ProcessThreadBlocks.second;
for (auto &B : Blocks) {
for (auto *R : B.Records) {
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp
index 8ccfd30..899a672 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp
@@ -20,7 +20,6 @@
#include "xray-registry.h"
#include "xray-color-helper.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/XRay/Trace.h"
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.h b/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.h
index 5d12c56..c2b2a93 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.h
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.h
@@ -15,7 +15,6 @@
#define XRAY_GRAPH_DIFF_H
#include "xray-graph.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/XRay/Graph.h"
namespace llvm {
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp
index d04b998..aebca90 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp
@@ -478,7 +478,7 @@
/// Prints top stacks for each thread.
void printPerThread(raw_ostream &OS, FuncIdConversionHelper &FN) {
- for (auto iter : Roots) {
+ for (const auto &iter : Roots) {
OS << "Thread " << iter.first << ":\n";
print(OS, FN, iter.second);
OS << "\n";
@@ -489,12 +489,8 @@
template <AggregationType AggType>
void printAllPerThread(raw_ostream &OS, FuncIdConversionHelper &FN,
StackOutputFormat format) {
- for (auto iter : Roots) {
- uint32_t threadId = iter.first;
- RootVector &perThreadRoots = iter.second;
- bool reportThreadId = true;
- printAll<AggType>(OS, FN, perThreadRoots, threadId, reportThreadId);
- }
+ for (const auto &iter : Roots)
+ printAll<AggType>(OS, FN, iter.second, iter.first, true);
}
/// Prints top stacks from looking at all the leaves and ignoring thread IDs.
@@ -521,7 +517,7 @@
/// thread IDs.
RootVector mergeAcrossThreads(std::forward_list<StackTrieNode> &NodeStore) {
RootVector MergedByThreadRoots;
- for (auto MapIter : Roots) {
+ for (const auto &MapIter : Roots) {
const auto &RootNodeVector = MapIter.second;
for (auto *Node : RootNodeVector) {
auto MaybeFoundIter =
diff --git a/src/llvm-project/llvm/tools/llvm-yaml-numeric-parser-fuzzer/yaml-numeric-parser-fuzzer.cpp b/src/llvm-project/llvm/tools/llvm-yaml-numeric-parser-fuzzer/yaml-numeric-parser-fuzzer.cpp
index c61b509..c837028 100644
--- a/src/llvm-project/llvm/tools/llvm-yaml-numeric-parser-fuzzer/yaml-numeric-parser-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-yaml-numeric-parser-fuzzer/yaml-numeric-parser-fuzzer.cpp
@@ -38,7 +38,7 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
std::string Input(reinterpret_cast<const char *>(Data), Size);
- llvm::erase_value(Input, 0);
+ llvm::erase(Input, 0);
if (!Input.empty() && llvm::yaml::isNumeric(Input) != isNumericRegex(Input))
LLVM_BUILTIN_TRAP;
return 0;
diff --git a/src/llvm-project/llvm/tools/llvm-yaml-parser-fuzzer/yaml-parser-fuzzer.cpp b/src/llvm-project/llvm/tools/llvm-yaml-parser-fuzzer/yaml-parser-fuzzer.cpp
index 007769f..b29920d 100644
--- a/src/llvm-project/llvm/tools/llvm-yaml-parser-fuzzer/yaml-parser-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-yaml-parser-fuzzer/yaml-parser-fuzzer.cpp
@@ -25,7 +25,7 @@
isValidYaml(Input.data(), Input.size());
// Ensure we don't crash on byte strings with no null characters.
- llvm::erase_value(Input, 0);
+ llvm::erase(Input, 0);
Input.shrink_to_fit();
bool IsValidWithout0s = isValidYaml(Input.data(), Input.size());
diff --git a/src/llvm-project/llvm/tools/lto/lto.cpp b/src/llvm-project/llvm/tools/lto/lto.cpp
index 22ebf54..ece6dd0 100644
--- a/src/llvm-project/llvm/tools/lto/lto.cpp
+++ b/src/llvm-project/llvm/tools/lto/lto.cpp
@@ -528,7 +528,7 @@
if (OptLevel < '0' || OptLevel > '3')
report_fatal_error("Optimization level must be between 0 and 3");
CodeGen->setOptLevel(OptLevel - '0');
- std::optional<CodeGenOpt::Level> CGOptLevelOrNone =
+ std::optional<CodeGenOptLevel> CGOptLevelOrNone =
CodeGenOpt::getLevel(OptLevel - '0');
assert(CGOptLevelOrNone);
CodeGen->setCodeGenOptLevel(*CGOptLevelOrNone);
diff --git a/src/llvm-project/llvm/tools/obj2yaml/archive2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/archive2yaml.cpp
index c7b0ee4..35bcd43 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/archive2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/archive2yaml.cpp
@@ -24,7 +24,7 @@
std::make_unique<ArchYAML::Archive>();
StringRef Magic = "!<arch>\n";
- if (!Buffer.startswith(Magic))
+ if (!Buffer.starts_with(Magic))
return createStringError(std::errc::not_supported,
"only regular archives are supported");
Obj->Magic = Magic;
diff --git a/src/llvm-project/llvm/tools/obj2yaml/coff2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/coff2yaml.cpp
index 604799f..2f80e62 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/coff2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/coff2yaml.cpp
@@ -123,7 +123,7 @@
cantFail(Obj.getSectionContents(COFFSection, sectionData));
- BinaryStreamReader Reader(sectionData, support::little);
+ BinaryStreamReader Reader(sectionData, llvm::endianness::little);
uint32_t Magic;
Err(Reader.readInteger(Magic));
diff --git a/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp
index 3d3798d..b3062c4 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp
@@ -22,15 +22,17 @@
using namespace llvm;
-void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+Error dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
auto AbbrevSetPtr = DCtx.getDebugAbbrev();
if (AbbrevSetPtr) {
uint64_t AbbrevTableID = 0;
- AbbrevSetPtr->parse();
- for (auto AbbrvDeclSet : *AbbrevSetPtr) {
+ if (Error Err = AbbrevSetPtr->parse())
+ return Err;
+ for (const auto &AbbrvDeclSet : *AbbrevSetPtr) {
Y.DebugAbbrev.emplace_back();
Y.DebugAbbrev.back().ID = AbbrevTableID++;
- for (auto AbbrvDecl : AbbrvDeclSet.second) {
+ for (const DWARFAbbreviationDeclaration &AbbrvDecl :
+ AbbrvDeclSet.second) {
DWARFYAML::Abbrev Abbrv;
Abbrv.Code = AbbrvDecl.getCode();
Abbrv.Tag = AbbrvDecl.getTag();
@@ -48,6 +50,7 @@
}
}
}
+ return Error::success();
}
Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
@@ -220,7 +223,12 @@
if (NewUnit.Version >= 5)
NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev();
- DebugAbbrev->parse();
+ // FIXME: Ideally we would propagate this error upwards, but that would
+ // prevent us from displaying any debug info at all. For now we just consume
+ // the error and display everything that was parsed successfully.
+ if (Error Err = DebugAbbrev->parse())
+ llvm::consumeError(std::move(Err));
+
NewUnit.AbbrevTableID = std::distance(
DebugAbbrev->begin(),
llvm::find_if(
diff --git a/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
index dd3bea6..b58d7cd 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
@@ -16,6 +16,16 @@
using namespace llvm;
using namespace llvm::object;
+static DXContainerYAML::Signature dumpSignature(const DirectX::Signature &Sig) {
+ DXContainerYAML::Signature YAML;
+ for (auto Param : Sig)
+ YAML.Parameters.push_back(DXContainerYAML::SignatureParameter{
+ Param.Stream, Sig.getName(Param.NameOffset).str(), Param.Index,
+ Param.SystemValue, Param.CompType, Param.Register, Param.Mask,
+ Param.ExclusiveMask, Param.MinPrecision});
+ return YAML;
+}
+
static Expected<DXContainerYAML::Object *>
dumpDXContainer(MemoryBufferRef Source) {
assert(file_magic::dxcontainer_object == identify_magic(Source.getBuffer()));
@@ -92,8 +102,52 @@
NewPart.Info->ResourceStride = PSVInfo->getResourceStride();
for (auto Res : PSVInfo->getResources())
NewPart.Info->Resources.push_back(Res);
+
+ for (auto El : PSVInfo->getSigInputElements())
+ NewPart.Info->SigInputElements.push_back(
+ DXContainerYAML::SignatureElement(
+ El, PSVInfo->getStringTable(),
+ PSVInfo->getSemanticIndexTable()));
+ for (auto El : PSVInfo->getSigOutputElements())
+ NewPart.Info->SigOutputElements.push_back(
+ DXContainerYAML::SignatureElement(
+ El, PSVInfo->getStringTable(),
+ PSVInfo->getSemanticIndexTable()));
+ for (auto El : PSVInfo->getSigPatchOrPrimElements())
+ NewPart.Info->SigPatchOrPrimElements.push_back(
+ DXContainerYAML::SignatureElement(
+ El, PSVInfo->getStringTable(),
+ PSVInfo->getSemanticIndexTable()));
+
+ if (PSVInfo->usesViewID()) {
+ for (int I = 0; I < 4; ++I)
+ for (auto Mask : PSVInfo->getOutputVectorMasks(I))
+ NewPart.Info->OutputVectorMasks[I].push_back(Mask);
+ for (auto Mask : PSVInfo->getPatchOrPrimMasks())
+ NewPart.Info->PatchOrPrimMasks.push_back(Mask);
+ }
+
+ for (int I = 0; I < 4; ++I)
+ for (auto Mask : PSVInfo->getInputOutputMap(I))
+ NewPart.Info->InputOutputMap[I].push_back(Mask);
+
+ for (auto Mask : PSVInfo->getInputPatchMap())
+ NewPart.Info->InputPatchMap.push_back(Mask);
+
+ for (auto Mask : PSVInfo->getPatchOutputMap())
+ NewPart.Info->PatchOutputMap.push_back(Mask);
+
break;
}
+ case dxbc::PartType::ISG1:
+ NewPart.Signature = dumpSignature(Container.getInputSignature());
+ break;
+ case dxbc::PartType::OSG1:
+ NewPart.Signature = dumpSignature(Container.getOutputSignature());
+ break;
+ case dxbc::PartType::PSG1:
+ NewPart.Signature = dumpSignature(Container.getPatchConstantSignature());
+ break;
case dxbc::PartType::Unknown:
break;
}
diff --git a/src/llvm-project/llvm/tools/obj2yaml/elf2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/elf2yaml.cpp
index b261b9d..86bd138 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "obj2yaml.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -300,7 +299,7 @@
}
// Normally an object that does not have sections has e_shnum == 0.
- // Also, e_shnum might be 0, when the the number of entries in the section
+ // Also, e_shnum might be 0, when the number of entries in the section
// header table is larger than or equal to SHN_LORESERVE (0xff00). In this
// case the real number of entries is held in the sh_size member of the
// initial entry. We have a section header table when `e_shoff` is not 0.
@@ -484,6 +483,7 @@
PH.Flags = Phdr.p_flags;
PH.VAddr = Phdr.p_vaddr;
PH.PAddr = Phdr.p_paddr;
+ PH.Offset = Phdr.p_offset;
// yaml2obj sets the alignment of a segment to 1 by default.
// We do not print the default alignment to reduce noise in the output.
@@ -514,7 +514,7 @@
std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections) {
DWARFYAML::Data DWARF;
for (std::unique_ptr<ELFYAML::Chunk> &C : Sections) {
- if (!C->Name.startswith(".debug_"))
+ if (!C->Name.starts_with(".debug_"))
continue;
if (ELFYAML::RawContentSection *RawSec =
diff --git a/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp
index c96b6cc..cdd871e 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp
@@ -15,6 +15,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/SystemZ/zOSSupport.h"
#include <string.h> // for memcpy
@@ -139,10 +140,8 @@
static Error dumpDebugSection(StringRef SecName, DWARFContext &DCtx,
DWARFYAML::Data &DWARF) {
- if (SecName == "__debug_abbrev") {
- dumpDebugAbbrev(DCtx, DWARF);
- return Error::success();
- }
+ if (SecName == "__debug_abbrev")
+ return dumpDebugAbbrev(DCtx, DWARF);
if (SecName == "__debug_aranges")
return dumpDebugARanges(DCtx, DWARF);
if (SecName == "__debug_info") {
@@ -153,7 +152,7 @@
dumpDebugLines(DCtx, DWARF);
return Error::success();
}
- if (SecName.startswith("__debug_pub")) {
+ if (SecName.starts_with("__debug_pub")) {
// FIXME: We should extract pub-section dumpers from this function.
dumpDebugPubSections(DCtx, DWARF);
return Error::success();
@@ -185,11 +184,11 @@
// Copy data sections if requested.
if ((RawSegment & ::RawSegments::data) &&
- StringRef(S->segname).startswith("__DATA"))
+ StringRef(S->segname).starts_with("__DATA"))
S->content =
yaml::BinaryRef(Obj.getSectionContents(Sec.offset, Sec.size));
- if (SecName.startswith("__debug_")) {
+ if (SecName.starts_with("__debug_")) {
// If the DWARF section cannot be successfully parsed, emit raw content
// instead of an entry in the DWARF section of the YAML.
if (Error Err = dumpDebugSection(SecName, *DWARFCtx, Y.DWARF))
@@ -533,7 +532,7 @@
* terminal.
*/
-const uint8_t *processExportNode(const uint8_t *CurrPtr,
+const uint8_t *processExportNode(const uint8_t *Start, const uint8_t *CurrPtr,
const uint8_t *const End,
MachOYAML::ExportEntry &Entry) {
if (CurrPtr >= End)
@@ -572,7 +571,7 @@
CurrPtr += Count;
}
for (auto &Child : Entry.Children) {
- CurrPtr = processExportNode(CurrPtr, End, Child);
+ CurrPtr = processExportNode(Start, Start + Child.NodeOffset, End, Child);
}
return CurrPtr;
}
@@ -583,7 +582,8 @@
auto ExportsTrie = Obj.getDyldInfoExportsTrie();
if (ExportsTrie.empty())
ExportsTrie = Obj.getDyldExportsTrie();
- processExportNode(ExportsTrie.begin(), ExportsTrie.end(), LEData.ExportTrie);
+ processExportNode(ExportsTrie.begin(), ExportsTrie.begin(), ExportsTrie.end(),
+ LEData.ExportTrie);
}
template <typename nlist_t>
diff --git a/src/llvm-project/llvm/tools/obj2yaml/obj2yaml.h b/src/llvm-project/llvm/tools/obj2yaml/obj2yaml.h
index e0204c6..03d7db5 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/obj2yaml.h
+++ b/src/llvm-project/llvm/tools/obj2yaml/obj2yaml.h
@@ -46,7 +46,7 @@
}
} // namespace llvm
-void dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+llvm::Error dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
llvm::Error dumpDebugAddr(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
llvm::Error dumpDebugARanges(llvm::DWARFContext &DCtx,
llvm::DWARFYAML::Data &Y);
diff --git a/src/llvm-project/llvm/tools/obj2yaml/wasm2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/wasm2yaml.cpp
index c450c02..c15d64c 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/wasm2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/wasm2yaml.cpp
@@ -44,7 +44,7 @@
const wasm::WasmTableType &Type) {
WasmYAML::Table T;
T.Index = Index;
- T.ElemType = Type.ElemType;
+ T.ElemType = (uint32_t)Type.ElemType;
T.TableLimits = makeLimits(Type.Limits);
return T;
}
@@ -205,7 +205,7 @@
std::unique_ptr<WasmYAML::Section> S;
switch (WasmSec.Type) {
case wasm::WASM_SEC_CUSTOM: {
- if (WasmSec.Name.startswith("reloc.")) {
+ if (WasmSec.Name.starts_with("reloc.")) {
// Relocations are attached the sections they apply to rather than
// being represented as a custom section in the YAML output.
continue;
@@ -334,7 +334,7 @@
WasmYAML::ElemSegment Seg;
Seg.Flags = Segment.Flags;
Seg.TableNumber = Segment.TableNumber;
- Seg.ElemKind = Segment.ElemKind;
+ Seg.ElemKind = (uint32_t)Segment.ElemKind;
Seg.Offset.Extended = Segment.Offset.Extended;
if (Seg.Offset.Extended) {
Seg.Offset.Body = yaml::BinaryRef(Segment.Offset.Body);
diff --git a/src/llvm-project/llvm/tools/obj2yaml/xcoff2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/xcoff2yaml.cpp
index 882c410..0acbf48 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/xcoff2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/xcoff2yaml.cpp
@@ -25,10 +25,30 @@
template <typename Shdr, typename Reloc>
Error dumpSections(ArrayRef<Shdr> Sections);
+ // Dump auxiliary symbols.
+ Error dumpFileAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef);
+ Error dumpStatAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef);
+ Error dumpBlockAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef);
+ Error dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef);
+ Error dumpAuxSyms(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef);
+ void dumpFuncAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress);
+ void dumpExpAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress);
+ void dumpCsectAuxSym(XCOFFYAML::Symbol &Sym,
+ const object::XCOFFCsectAuxRef &AuxEntPtr);
+
public:
XCOFFDumper(const object::XCOFFObjectFile &obj) : Obj(obj) {}
Error dump();
XCOFFYAML::Object &getYAMLObj() { return YAMLObj; }
+
+ template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress) {
+ Obj.checkSymbolEntryPointer(AuxAddress);
+ return reinterpret_cast<const T *>(AuxAddress);
+ }
};
} // namespace
@@ -106,6 +126,210 @@
return Error::success();
}
+Error XCOFFDumper::dumpFileAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef) {
+ for (uint8_t I = 1; I <= Sym.NumberOfAuxEntries; ++I) {
+ uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
+ SymbolEntRef.getEntryAddress(), I);
+ const XCOFFFileAuxEnt *FileAuxEntPtr =
+ getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
+ auto FileNameOrError = Obj.getCFileName(FileAuxEntPtr);
+ if (!FileNameOrError)
+ return FileNameOrError.takeError();
+
+ XCOFFYAML::FileAuxEnt FileAuxSym;
+ FileAuxSym.FileNameOrString = FileNameOrError.get();
+ FileAuxSym.FileStringType = FileAuxEntPtr->Type;
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::FileAuxEnt>(FileAuxSym));
+ }
+ return Error::success();
+}
+
+Error XCOFFDumper::dumpStatAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef) {
+ if (Sym.NumberOfAuxEntries != 1) {
+ uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
+ return createError("failed to parse symbol \"" + Sym.SymbolName +
+ "\" with index of " + Twine(SymbolIndex) +
+ ": expected 1 aux symbol for C_STAT, while got " +
+ Twine(static_cast<uint32_t>(*Sym.NumberOfAuxEntries)));
+ }
+
+ const XCOFFSectAuxEntForStat *AuxEntPtr =
+ getAuxEntPtr<XCOFFSectAuxEntForStat>(
+ XCOFFObjectFile::getAdvancedSymbolEntryAddress(
+ SymbolEntRef.getEntryAddress(), 1));
+ XCOFFYAML::SectAuxEntForStat StatAuxSym;
+ StatAuxSym.SectionLength = AuxEntPtr->SectionLength;
+ StatAuxSym.NumberOfLineNum = AuxEntPtr->NumberOfLineNum;
+ StatAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt;
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::SectAuxEntForStat>(StatAuxSym));
+ return Error::success();
+}
+
+void XCOFFDumper::dumpFuncAuxSym(XCOFFYAML::Symbol &Sym,
+ const uintptr_t AuxAddress) {
+ XCOFFYAML::FunctionAuxEnt FunAuxSym;
+
+ if (Obj.is64Bit()) {
+ const XCOFFFunctionAuxEnt64 *AuxEntPtr =
+ getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress);
+ FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum;
+ FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction;
+ FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond;
+ } else {
+ const XCOFFFunctionAuxEnt32 *AuxEntPtr =
+ getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
+ FunAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl;
+ FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum;
+ FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction;
+ FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond;
+ }
+
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::FunctionAuxEnt>(FunAuxSym));
+}
+
+void XCOFFDumper::dumpExpAuxSym(XCOFFYAML::Symbol &Sym,
+ const uintptr_t AuxAddress) {
+ const XCOFFExceptionAuxEnt *AuxEntPtr =
+ getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
+ XCOFFYAML::ExcpetionAuxEnt ExceptAuxSym;
+ ExceptAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl;
+ ExceptAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction;
+ ExceptAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond;
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::ExcpetionAuxEnt>(ExceptAuxSym));
+}
+
+void XCOFFDumper::dumpCsectAuxSym(XCOFFYAML::Symbol &Sym,
+ const object::XCOFFCsectAuxRef &AuxEntPtr) {
+ XCOFFYAML::CsectAuxEnt CsectAuxSym;
+ CsectAuxSym.ParameterHashIndex = AuxEntPtr.getParameterHashIndex();
+ CsectAuxSym.TypeChkSectNum = AuxEntPtr.getTypeChkSectNum();
+ CsectAuxSym.SymbolAlignmentAndType = AuxEntPtr.getSymbolAlignmentAndType();
+ CsectAuxSym.StorageMappingClass = AuxEntPtr.getStorageMappingClass();
+
+ if (Obj.is64Bit()) {
+ CsectAuxSym.SectionOrLengthLo =
+ static_cast<uint32_t>(AuxEntPtr.getSectionOrLength64());
+ CsectAuxSym.SectionOrLengthHi =
+ static_cast<uint32_t>(AuxEntPtr.getSectionOrLength64() >> 32);
+ } else {
+ CsectAuxSym.SectionOrLength = AuxEntPtr.getSectionOrLength32();
+ CsectAuxSym.StabInfoIndex = AuxEntPtr.getStabInfoIndex32();
+ CsectAuxSym.StabSectNum = AuxEntPtr.getStabSectNum32();
+ }
+
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::CsectAuxEnt>(CsectAuxSym));
+}
+
+Error XCOFFDumper::dumpAuxSyms(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef) {
+ auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
+ if (!ErrOrCsectAuxRef)
+ return ErrOrCsectAuxRef.takeError();
+ XCOFFCsectAuxRef CsectAuxRef = ErrOrCsectAuxRef.get();
+
+ for (uint8_t I = 1; I <= Sym.NumberOfAuxEntries; ++I) {
+
+ if (I == Sym.NumberOfAuxEntries && !Obj.is64Bit()) {
+ dumpCsectAuxSym(Sym, CsectAuxRef);
+ return Error::success();
+ }
+
+ uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
+ SymbolEntRef.getEntryAddress(), I);
+
+ if (Obj.is64Bit()) {
+ XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
+ if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
+ dumpCsectAuxSym(Sym, CsectAuxRef);
+ else if (Type == XCOFF::SymbolAuxType::AUX_FCN)
+ dumpFuncAuxSym(Sym, AuxAddress);
+ else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT)
+ dumpExpAuxSym(Sym, AuxAddress);
+ else {
+ uint32_t SymbolIndex =
+ Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
+ return createError("failed to parse symbol \"" + Sym.SymbolName +
+ "\" with index of " + Twine(SymbolIndex) +
+ ": invalid auxiliary symbol type: " +
+ Twine(static_cast<uint32_t>(Type)));
+ }
+
+ } else
+ dumpFuncAuxSym(Sym, AuxAddress);
+ }
+
+ return Error::success();
+}
+
+Error XCOFFDumper::dumpBlockAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef) {
+ if (Sym.NumberOfAuxEntries != 1) {
+ uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
+ return createError(
+ "failed to parse symbol \"" + Sym.SymbolName + "\" with index of " +
+ Twine(SymbolIndex) +
+ ": expected 1 aux symbol for C_BLOCK or C_FCN, while got " +
+ Twine(static_cast<uint32_t>(*Sym.NumberOfAuxEntries)));
+ }
+
+ uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
+ SymbolEntRef.getEntryAddress(), 1);
+ XCOFFYAML::BlockAuxEnt BlockAuxSym;
+
+ if (Obj.is64Bit()) {
+ const XCOFFBlockAuxEnt64 *AuxEntPtr =
+ getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
+ BlockAuxSym.LineNum = AuxEntPtr->LineNum;
+ } else {
+ const XCOFFBlockAuxEnt32 *AuxEntPtr =
+ getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
+ BlockAuxSym.LineNumLo = AuxEntPtr->LineNumLo;
+ BlockAuxSym.LineNumHi = AuxEntPtr->LineNumHi;
+ }
+
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::BlockAuxEnt>(BlockAuxSym));
+ return Error::success();
+}
+
+Error XCOFFDumper::dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym,
+ const XCOFFSymbolRef &SymbolEntRef) {
+ if (Sym.NumberOfAuxEntries != 1) {
+ uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
+ return createError("failed to parse symbol \"" + Sym.SymbolName +
+ "\" with index of " + Twine(SymbolIndex) +
+ ": expected 1 aux symbol for C_DWARF, while got " +
+ Twine(static_cast<uint32_t>(*Sym.NumberOfAuxEntries)));
+ }
+
+ uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
+ SymbolEntRef.getEntryAddress(), 1);
+ XCOFFYAML::SectAuxEntForDWARF DwarfAuxSym;
+
+ if (Obj.is64Bit()) {
+ const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
+ getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
+ DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion;
+ DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt;
+ } else {
+ const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
+ getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
+ DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion;
+ DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt;
+ }
+
+ Sym.AuxEntries.push_back(
+ std::make_unique<XCOFFYAML::SectAuxEntForDWARF>(DwarfAuxSym));
+ return Error::success();
+}
+
Error XCOFFDumper::dumpSymbols() {
std::vector<XCOFFYAML::Symbol> &Symbols = YAMLObj.Symbols;
@@ -133,6 +357,36 @@
Sym.StorageClass = SymbolEntRef.getStorageClass();
Sym.NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
+ if (Sym.NumberOfAuxEntries) {
+ switch (Sym.StorageClass) {
+ case XCOFF::C_FILE:
+ if (Error E = dumpFileAuxSym(Sym, SymbolEntRef))
+ return E;
+ break;
+ case XCOFF::C_STAT:
+ if (Error E = dumpStatAuxSym(Sym, SymbolEntRef))
+ return E;
+ break;
+ case XCOFF::C_EXT:
+ case XCOFF::C_WEAKEXT:
+ case XCOFF::C_HIDEXT:
+ if (Error E = dumpAuxSyms(Sym, SymbolEntRef))
+ return E;
+ break;
+ case XCOFF::C_BLOCK:
+ case XCOFF::C_FCN:
+ if (Error E = dumpBlockAuxSym(Sym, SymbolEntRef))
+ return E;
+ break;
+ case XCOFF::C_DWARF:
+ if (Error E = dumpDwarfAuxSym(Sym, SymbolEntRef))
+ return E;
+ break;
+ default:
+ break;
+ }
+ }
+
Symbols.push_back(std::move(Sym));
}
diff --git a/src/llvm-project/llvm/tools/opt/opt.cpp b/src/llvm-project/llvm/tools/opt/opt.cpp
index 9c20e77..8c0e989 100644
--- a/src/llvm-project/llvm/tools/opt/opt.cpp
+++ b/src/llvm-project/llvm/tools/opt/opt.cpp
@@ -39,6 +39,7 @@
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Remarks/HotnessThresholdParser.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/PluginLoader.h"
@@ -149,34 +150,32 @@
StripNamedMetadata("strip-named-metadata",
cl::desc("Strip module-level named metadata"));
-
-
static cl::opt<bool>
OptLevelO0("O0", cl::desc("Optimization level 0. Similar to clang -O0. "
- "Use -passes='default<O0>' for the new PM"));
+ "Same as -passes='default<O0>'"));
static cl::opt<bool>
OptLevelO1("O1", cl::desc("Optimization level 1. Similar to clang -O1. "
- "Use -passes='default<O1>' for the new PM"));
+ "Same as -passes='default<O1>'"));
static cl::opt<bool>
OptLevelO2("O2", cl::desc("Optimization level 2. Similar to clang -O2. "
- "Use -passes='default<O2>' for the new PM"));
+ "Same as -passes='default<O2>'"));
static cl::opt<bool>
OptLevelOs("Os", cl::desc("Like -O2 but size-conscious. Similar to clang "
- "-Os. Use -passes='default<Os>' for the new PM"));
+ "-Os. Same as -passes='default<Os>'"));
static cl::opt<bool> OptLevelOz(
"Oz",
cl::desc("Like -O2 but optimize for code size above all else. Similar to "
- "clang -Oz. Use -passes='default<Oz>' for the new PM"));
+ "clang -Oz. Same as -passes='default<Oz>'"));
static cl::opt<bool>
OptLevelO3("O3", cl::desc("Optimization level 3. Similar to clang -O3. "
- "Use -passes='default<O3>' for the new PM"));
+ "Same as -passes='default<O3>'"));
-static cl::opt<unsigned> CodeGenOptLevel(
+static cl::opt<unsigned> CodeGenOptLevelCL(
"codegen-opt-level",
cl::desc("Override optimization level for codegen hooks, legacy PM only"));
@@ -280,30 +279,19 @@
PassPlugins("load-pass-plugin",
cl::desc("Load passes from plugin library"));
+static cl::opt<bool> TryUseNewDbgInfoFormat(
+ "try-experimental-debuginfo-iterators",
+ cl::desc("Enable debuginfo iterator positions, if they're built in"),
+ cl::init(false), cl::Hidden);
+
+extern cl::opt<bool> UseNewDbgInfoFormat;
+
//===----------------------------------------------------------------------===//
// CodeGen-related helper functions.
//
-static CodeGenOpt::Level GetCodeGenOptLevel() {
- return static_cast<CodeGenOpt::Level>(unsigned(CodeGenOptLevel));
-}
-
-// Returns the TargetMachine instance or zero if no triple is provided.
-static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr,
- StringRef FeaturesStr,
- const TargetOptions &Options) {
- std::string Error;
- const Target *TheTarget =
- TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
- // Some modules don't specify a triple, and this is okay.
- if (!TheTarget) {
- return nullptr;
- }
-
- return TheTarget->createTargetMachine(
- TheTriple.getTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(),
- Options, codegen::getExplicitRelocModel(),
- codegen::getExplicitCodeModel(), GetCodeGenOptLevel());
+static CodeGenOptLevel GetCodeGenOptLevel() {
+ return static_cast<CodeGenOptLevel>(unsigned(CodeGenOptLevelCL));
}
struct TimeTracerRAII {
@@ -333,6 +321,7 @@
"nvvm-reflect",
"nvvm-intr-range",
"amdgpu-simplifylib",
+ "amdgpu-image-intrinsic-opt",
"amdgpu-usenative",
"amdgpu-promote-alloca",
"amdgpu-promote-alloca-to-vector",
@@ -350,7 +339,7 @@
"nvptx-", "mips-", "lanai-", "hexagon-", "bpf-", "avr-",
"thumb2-", "arm-", "si-", "gcn-", "amdgpu-", "aarch64-",
"amdgcn-", "polly-", "riscv-", "dxil-"};
- std::vector<StringRef> PassNameContain = {"ehprepare"};
+ std::vector<StringRef> PassNameContain = {"-eh-prepare"};
std::vector<StringRef> PassNameExact = {
"safe-stack",
"cost-model",
@@ -367,15 +356,14 @@
"expand-reductions",
"indirectbr-expand",
"generic-to-nvvm",
- "expandmemcmp",
+ "expand-memcmp",
"loop-reduce",
"lower-amx-type",
- "pre-amx-config",
"lower-amx-intrinsics",
"polyhedral-info",
"print-polyhedral-info",
"replace-with-veclib",
- "jmc-instrument",
+ "jmc-instrumenter",
"dot-regions",
"dot-regions-only",
"view-regions",
@@ -388,7 +376,7 @@
"callbrprepare",
};
for (const auto &P : PassNamePrefix)
- if (Pass.startswith(P))
+ if (Pass.starts_with(P))
return true;
for (const auto &P : PassNameContain)
if (Pass.contains(P))
@@ -434,11 +422,11 @@
// supported.
initializeExpandLargeDivRemLegacyPassPass(Registry);
initializeExpandLargeFpConvertLegacyPassPass(Registry);
- initializeExpandMemCmpPassPass(Registry);
+ initializeExpandMemCmpLegacyPassPass(Registry);
initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry);
initializeSelectOptimizePass(Registry);
initializeCallBrPreparePass(Registry);
- initializeCodeGenPreparePass(Registry);
+ initializeCodeGenPrepareLegacyPassPass(Registry);
initializeAtomicExpandPass(Registry);
initializeWinEHPreparePass(Registry);
initializeDwarfEHPrepareLegacyPassPass(Registry);
@@ -446,7 +434,7 @@
initializeSjLjEHPreparePass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeGlobalMergePass(Registry);
- initializeIndirectBrExpandPassPass(Registry);
+ initializeIndirectBrExpandLegacyPassPass(Registry);
initializeInterleavedLoadCombinePass(Registry);
initializeInterleavedAccessPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
@@ -460,11 +448,8 @@
SmallVector<PassPlugin, 1> PluginList;
PassPlugins.setCallback([&](const std::string &PluginPath) {
auto Plugin = PassPlugin::Load(PluginPath);
- if (!Plugin) {
- errs() << "Failed to load passes from '" << PluginPath
- << "'. Request ignored.\n";
- return;
- }
+ if (!Plugin)
+ report_fatal_error(Plugin.takeError(), /*gen_crash_diag=*/false);
PluginList.emplace_back(Plugin.get());
});
@@ -474,6 +459,17 @@
cl::ParseCommandLineOptions(argc, argv,
"llvm .bc -> .bc modular optimizer and analysis printer\n");
+ // RemoveDIs debug-info transition: tests may request that we /try/ to use the
+ // new debug-info format, if it's built in.
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ if (TryUseNewDbgInfoFormat) {
+ // If LLVM was built with support for this, turn the new debug-info format
+ // on.
+ UseNewDbgInfoFormat = true;
+ }
+#endif
+ (void)TryUseNewDbgInfoFormat;
+
LLVMContext Context;
// TODO: remove shouldForceLegacyPM().
@@ -522,10 +518,36 @@
std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
// Load the input module...
- auto SetDataLayout = [](StringRef, StringRef) -> std::optional<std::string> {
- if (ClDataLayout.empty())
+ auto SetDataLayout = [&](StringRef IRTriple,
+ StringRef IRLayout) -> std::optional<std::string> {
+ // Data layout specified on the command line has the highest priority.
+ if (!ClDataLayout.empty())
+ return ClDataLayout;
+ // If an explicit data layout is already defined in the IR, don't infer.
+ if (!IRLayout.empty())
return std::nullopt;
- return ClDataLayout;
+
+ // If an explicit triple was specified (either in the IR or on the
+ // command line), use that to infer the default data layout. However, the
+ // command line target triple should override the IR file target triple.
+ std::string TripleStr =
+ TargetTriple.empty() ? IRTriple.str() : Triple::normalize(TargetTriple);
+ // If the triple string is still empty, we don't fall back to
+ // sys::getDefaultTargetTriple() since we do not want to have differing
+ // behaviour dependent on the configured default triple. Therefore, if the
+ // user did not pass -mtriple or define an explicit triple/datalayout in
+ // the IR, we should default to an empty (default) DataLayout.
+ if (TripleStr.empty())
+ return std::nullopt;
+ // Otherwise we infer the DataLayout from the target machine.
+ Expected<std::unique_ptr<TargetMachine>> ExpectedTM =
+ codegen::createTargetMachineForTriple(TripleStr, GetCodeGenOptLevel());
+ if (!ExpectedTM) {
+ errs() << argv[0] << ": warning: failed to infer data layout: "
+ << toString(ExpectedTM.takeError()) << "\n";
+ return std::nullopt;
+ }
+ return (*ExpectedTM)->createDataLayout().getStringRepresentation();
};
std::unique_ptr<Module> M;
if (NoUpgradeDebugInfo)
@@ -553,7 +575,7 @@
}
}
- // If we are supposed to override the target triple or data layout, do so now.
+ // If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
M->setTargetTriple(Triple::normalize(TargetTriple));
@@ -570,9 +592,14 @@
// the facility for updating public visibility to linkage unit visibility when
// specified by an internal option. This is normally done during LTO which is
// not performed via opt.
- updateVCallVisibilityInModule(*M,
- /* WholeProgramVisibilityEnabledInLTO */ false,
- /* DynamicExportSymbols */ {});
+ updateVCallVisibilityInModule(
+ *M,
+ /*WholeProgramVisibilityEnabledInLTO=*/false,
+ // FIXME: These need linker information via a
+ // TBD new interface.
+ /*DynamicExportSymbols=*/{},
+ /*ValidateAllVtablesHaveTypeInfos=*/false,
+ /*IsVisibleToRegularObj=*/[](StringRef) { return true; });
// Figure out what stream we are supposed to write to...
std::unique_ptr<ToolOutputFile> Out;
@@ -607,14 +634,19 @@
Triple ModuleTriple(M->getTargetTriple());
std::string CPUStr, FeaturesStr;
- TargetMachine *Machine = nullptr;
- const TargetOptions Options =
- codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple);
-
+ std::unique_ptr<TargetMachine> TM;
if (ModuleTriple.getArch()) {
CPUStr = codegen::getCPUStr();
FeaturesStr = codegen::getFeaturesStr();
- Machine = GetTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options);
+ Expected<std::unique_ptr<TargetMachine>> ExpectedTM =
+ codegen::createTargetMachineForTriple(ModuleTriple.str(),
+ GetCodeGenOptLevel());
+ if (auto E = ExpectedTM.takeError()) {
+ errs() << argv[0] << ": WARNING: failed to create target machine for '"
+ << ModuleTriple.str() << "': " << toString(std::move(E)) << "\n";
+ } else {
+ TM = std::move(*ExpectedTM);
+ }
} else if (ModuleTriple.getArchName() != "unknown" &&
ModuleTriple.getArchName() != "") {
errs() << argv[0] << ": unrecognized architecture '"
@@ -622,8 +654,6 @@
return 1;
}
- std::unique_ptr<TargetMachine> TM(Machine);
-
// Override function attributes based on CPUStr, FeaturesStr, and command line
// flags.
codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M);
diff --git a/src/llvm-project/llvm/tools/sancov/CMakeLists.txt b/src/llvm-project/llvm/tools/sancov/CMakeLists.txt
index 3fc1cac..a174ddf 100644
--- a/src/llvm-project/llvm/tools/sancov/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/sancov/CMakeLists.txt
@@ -5,11 +5,20 @@
MC
MCDisassembler
Object
+ Option
Support
Symbolize
TargetParser
)
+set(LLVM_TARGET_DEFINITIONS Opts.td)
+tablegen(LLVM Opts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(SancovOptsTableGen)
+
add_llvm_tool(sancov
sancov.cpp
+
+ DEPENDS
+ SancovOptsTableGen
+ GENERATE_DRIVER
)
diff --git a/src/llvm-project/llvm/tools/sancov/Opts.td b/src/llvm-project/llvm/tools/sancov/Opts.td
new file mode 100644
index 0000000..2e8af81
--- /dev/null
+++ b/src/llvm-project/llvm/tools/sancov/Opts.td
@@ -0,0 +1,58 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name, string help> : Flag<["-", "--"], name>, HelpText<help>;
+
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["-", "--"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["-", "--"], "no-" # name>, HelpText<help2>;
+}
+
+multiclass Eq<string name, string help> {
+ def NAME #_EQ : Joined<["-", "--"], name #"=">,
+ HelpText<help>;
+ def : Separate<["-", "--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
+}
+
+def generic_grp : OptionGroup<"Genric Options">, HelpText<"Generic Options">;
+def help : F<"help", "Display this help">, Group<generic_grp>;
+def : Flag<["-"], "h">, Alias<help>, HelpText<"Alias for --help">, Group<generic_grp>;
+def version : F<"version", "Display the version">, Group<generic_grp>;
+def : Flag<["-"], "v">, Alias<version>, HelpText<"Alias for --version">, Group<generic_grp>;
+
+def action_grp : OptionGroup<"Action">, HelpText<"Action (required)">;
+def print : F<"print", "Print coverage addresses">,
+ Group<action_grp>;
+def printCoveragePcs : F<"print-coverage-pcs", "Print coverage instrumentation points addresses.">,
+ Group<action_grp>;
+def coveredFunctions : F<"covered-functions", "Print all covered funcions.">,
+ Group<action_grp>;
+def notCoveredFunctions : F<"not-covered-functions", "Print all not covered funcions.">,
+ Group<action_grp>;
+def printCoverageStats : F<"print-coverage-stats", "Print coverage statistics.">,
+ Group<action_grp>;
+def htmlReport : F<"html-report", "REMOVED. Use -symbolize & coverage-report-server.py.">,
+ Group<action_grp>;
+def symbolize : F<"symbolize", "Produces a symbolized JSON report from binary report.">,
+ Group<action_grp>;
+def merge : F<"merge", "Merges reports.">,
+ Group<action_grp>;
+
+defm demangle : B<"demangle", "Demangle function names", "Do not demangle function names">;
+defm skipDeadFiles : B<"skip-dead-files", "Do not list dead source files in reports",
+ "List dead source files in reports">;
+defm useDefaultIgnoreList :
+ B<"use_default_ignorelist", "Use the default ignore list", "Don't use the default ignore list">,
+ Flags<[HelpHidden]>;
+
+// Compatibility aliases
+def : Flag<["-"], "demangle=0">, Alias<no_demangle>, HelpText<"Alias for --no-demangle">;
+def : Flag<["-"], "skip-dead-files=0">, Alias<no_skipDeadFiles>, HelpText<"Alias for --no-skip-dead-files">;
+def : Flag<["-"], "use_default_ignorelist=0">, Alias<no_useDefaultIgnoreList>, HelpText<"Alias for --no-use_default_ignore_list">;
+
+defm stripPathPrefix
+ : Eq<"strip_path_prefix", "Strip this prefix from files paths in reports">,
+ MetaVarName<"<string>">;
+
+defm ignorelist
+ : Eq<"ignorelist", "Ignorelist file (sanitizer ignorelist format)">,
+ MetaVarName<"<string>">;
diff --git a/src/llvm-project/llvm/tools/sancov/sancov.cpp b/src/llvm-project/llvm/tools/sancov/sancov.cpp
index 9d29e9a..e5b0875 100644
--- a/src/llvm-project/llvm/tools/sancov/sancov.cpp
+++ b/src/llvm-project/llvm/tools/sancov/sancov.cpp
@@ -29,13 +29,15 @@
#include "llvm/Object/COFF.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -55,9 +57,36 @@
namespace {
-// --------- COMMAND LINE FLAGS ---------
+// Command-line option boilerplate.
+namespace {
+using namespace llvm::opt;
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
+};
-cl::OptionCategory Cat("sancov Options");
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
+#include "Opts.inc"
+#undef PREFIX
+
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
+};
+
+class SancovOptTable : public opt::GenericOptTable {
+public:
+ SancovOptTable() : GenericOptTable(InfoTable) {}
+};
+} // namespace
+
+// --------- COMMAND LINE FLAGS ---------
enum ActionType {
CoveredFunctionsAction,
@@ -70,53 +99,13 @@
SymbolizeAction
};
-cl::opt<ActionType> Action(
- cl::desc("Action (required)"), cl::Required,
- cl::values(
- clEnumValN(PrintAction, "print", "Print coverage addresses"),
- clEnumValN(PrintCovPointsAction, "print-coverage-pcs",
- "Print coverage instrumentation points addresses."),
- clEnumValN(CoveredFunctionsAction, "covered-functions",
- "Print all covered funcions."),
- clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",
- "Print all not covered funcions."),
- clEnumValN(StatsAction, "print-coverage-stats",
- "Print coverage statistics."),
- clEnumValN(HtmlReportAction, "html-report",
- "REMOVED. Use -symbolize & coverage-report-server.py."),
- clEnumValN(SymbolizeAction, "symbolize",
- "Produces a symbolized JSON report from binary report."),
- clEnumValN(MergeAction, "merge", "Merges reports.")),
- cl::cat(Cat));
-
-static cl::list<std::string>
- ClInputFiles(cl::Positional, cl::OneOrMore,
- cl::desc("<action> <binary files...> <.sancov files...> "
- "<.symcov files...>"),
- cl::cat(Cat));
-
-static cl::opt<bool> ClDemangle("demangle", cl::init(true),
- cl::desc("Print demangled function name"),
- cl::cat(Cat));
-
-static cl::opt<bool>
- ClSkipDeadFiles("skip-dead-files", cl::init(true),
- cl::desc("Do not list dead source files in reports"),
- cl::cat(Cat));
-
-static cl::opt<std::string>
- ClStripPathPrefix("strip_path_prefix", cl::init(""),
- cl::desc("Strip this prefix from file paths in reports"),
- cl::cat(Cat));
-
-static cl::opt<std::string>
- ClIgnorelist("ignorelist", cl::init(""),
- cl::desc("Ignorelist file (sanitizer ignorelist format)"),
- cl::cat(Cat));
-
-static cl::opt<bool> ClUseDefaultIgnorelist(
- "use_default_ignorelist", cl::init(true), cl::Hidden,
- cl::desc("Controls if default ignorelist should be used"), cl::cat(Cat));
+static ActionType Action;
+static std::vector<std::string> ClInputFiles;
+static bool ClDemangle;
+static bool ClSkipDeadFiles;
+static bool ClUseDefaultIgnorelist;
+static std::string ClStripPathPrefix;
+static std::string ClIgnorelist;
static const char *const DefaultIgnorelistStr = "fun:__sanitizer_.*\n"
"src:/usr/include/.*\n"
@@ -699,8 +688,7 @@
// Ported from
// compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h:GetPreviousInstructionPc
// GetPreviousInstructionPc.
-static uint64_t getPreviousInstructionPc(uint64_t PC,
- Triple TheTriple) {
+static uint64_t getPreviousInstructionPc(uint64_t PC, Triple TheTriple) {
if (TheTriple.isARM())
return (PC - 3) & (~1);
if (TheTriple.isMIPS() || TheTriple.isSPARC())
@@ -1145,31 +1133,99 @@
} // namespace
-int main(int Argc, char **Argv) {
- llvm::InitLLVM X(Argc, Argv);
- cl::HideUnrelatedOptions(Cat);
+static void parseArgs(int Argc, char **Argv) {
+ SancovOptTable Tbl;
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver{A};
+ opt::InputArgList Args =
+ Tbl.parseArgs(Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
+ llvm::errs() << Msg << '\n';
+ std::exit(1);
+ });
+ if (Args.hasArg(OPT_help)) {
+ Tbl.printHelp(
+ llvm::outs(),
+ "sancov [options] <action> <binary files...> <.sancov files...> "
+ "<.symcov files...>",
+ "Sanitizer Coverage Processing Tool (sancov)\n\n"
+ " This tool can extract various coverage-related information from: \n"
+ " coverage-instrumented binary files, raw .sancov files and their "
+ "symbolized .symcov version.\n"
+ " Depending on chosen action the tool expects different input files:\n"
+ " -print-coverage-pcs - coverage-instrumented binary files\n"
+ " -print-coverage - .sancov files\n"
+ " <other actions> - .sancov files & corresponding binary "
+ "files, .symcov files\n");
+ std::exit(0);
+ }
+
+ if (Args.hasArg(OPT_version)) {
+ cl::PrintVersionMessage();
+ std::exit(0);
+ }
+
+ if (Args.hasMultipleArgs(OPT_action_grp)) {
+ fail("Only one action option is allowed");
+ }
+
+ for (const opt::Arg *A : Args.filtered(OPT_INPUT)) {
+ ClInputFiles.emplace_back(A->getValue());
+ }
+
+ if (const llvm::opt::Arg *A = Args.getLastArg(OPT_action_grp)) {
+ switch (A->getOption().getID()) {
+ case OPT_print:
+ Action = ActionType::PrintAction;
+ break;
+ case OPT_printCoveragePcs:
+ Action = ActionType::PrintCovPointsAction;
+ break;
+ case OPT_coveredFunctions:
+ Action = ActionType::CoveredFunctionsAction;
+ break;
+ case OPT_notCoveredFunctions:
+ Action = ActionType::NotCoveredFunctionsAction;
+ break;
+ case OPT_printCoverageStats:
+ Action = ActionType::StatsAction;
+ break;
+ case OPT_htmlReport:
+ Action = ActionType::HtmlReportAction;
+ break;
+ case OPT_symbolize:
+ Action = ActionType::SymbolizeAction;
+ break;
+ case OPT_merge:
+ Action = ActionType::MergeAction;
+ break;
+ default:
+ fail("Invalid Action");
+ }
+ }
+
+ ClDemangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ ClSkipDeadFiles = Args.hasFlag(OPT_skipDeadFiles, OPT_no_skipDeadFiles, true);
+ ClUseDefaultIgnorelist =
+ Args.hasFlag(OPT_useDefaultIgnoreList, OPT_no_useDefaultIgnoreList, true);
+
+ ClStripPathPrefix = Args.getLastArgValue(OPT_stripPathPrefix_EQ);
+ ClIgnorelist = Args.getLastArgValue(OPT_ignorelist_EQ);
+}
+
+int sancov_main(int Argc, char **Argv, const llvm::ToolContext &) {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
- cl::ParseCommandLineOptions(Argc, Argv,
- "Sanitizer Coverage Processing Tool (sancov)\n\n"
- " This tool can extract various coverage-related information from: \n"
- " coverage-instrumented binary files, raw .sancov files and their "
- "symbolized .symcov version.\n"
- " Depending on chosen action the tool expects different input files:\n"
- " -print-coverage-pcs - coverage-instrumented binary files\n"
- " -print-coverage - .sancov files\n"
- " <other actions> - .sancov files & corresponding binary "
- "files, .symcov files\n"
- );
+ parseArgs(Argc, Argv);
// -print doesn't need object files.
if (Action == PrintAction) {
readAndPrintRawCoverage(ClInputFiles, outs());
return 0;
- } else if (Action == PrintCovPointsAction) {
+ }
+ if (Action == PrintCovPointsAction) {
// -print-coverage-points doesn't need coverage files.
for (const std::string &ObjFile : ClInputFiles) {
printCovPoints(ObjFile, outs());
@@ -1207,4 +1263,6 @@
case PrintCovPointsAction:
llvm_unreachable("unsupported action");
}
+
+ return 0;
}
diff --git a/src/llvm-project/llvm/tools/spirv-tools/CMakeLists.txt b/src/llvm-project/llvm/tools/spirv-tools/CMakeLists.txt
new file mode 100644
index 0000000..f73dcad
--- /dev/null
+++ b/src/llvm-project/llvm/tools/spirv-tools/CMakeLists.txt
@@ -0,0 +1,65 @@
+option(LLVM_INCLUDE_SPIRV_TOOLS_TESTS "Include tests that use SPIRV-Tools" Off)
+mark_as_advanced(LLVM_INCLUDE_SPIRV_TOOLS_TESTS)
+
+if (NOT LLVM_INCLUDE_SPIRV_TOOLS_TESTS)
+ return()
+endif ()
+
+if (NOT "SPIRV" IN_LIST LLVM_TARGETS_TO_BUILD)
+ message(FATAL_ERROR "Building SPIRV-Tools tests is unsupported without the SPIR-V target")
+endif ()
+
+# SPIRV_DIS and SPIRV_VAL variables can be used to provide paths to existing
+# spirv-dis and spirv-val binaries, respectively. Otherwise, build them from
+# SPIRV-Tools source.
+if (NOT SPIRV_DIS OR NOT SPIRV_VAL)
+ include(ExternalProject)
+
+ set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/SPIRVTools-bin)
+
+ ExternalProject_Add(SPIRVTools
+ GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Tools.git
+ GIT_TAG main
+ BINARY_DIR ${BINARY_DIR}
+ BUILD_COMMAND ${CMAKE_COMMAND} --build ${BINARY_DIR} --target spirv-dis spirv-val
+ BUILD_BYPRODUCTS ${BINARY_DIR}/tools/spirv-dis ${BINARY_DIR}/tools/spirv-val
+ DOWNLOAD_COMMAND git clone https://github.com/KhronosGroup/SPIRV-Tools.git SPIRVTools &&
+ cd SPIRVTools &&
+ ${Python3_EXECUTABLE} utils/git-sync-deps
+ UPDATE_COMMAND git pull origin main &&
+ ${Python3_EXECUTABLE} utils/git-sync-deps
+ # Don't auto-update on every build.
+ UPDATE_DISCONNECTED 1
+ # Allow manual updating with an explicit SPIRVTools-update target.
+ STEP_TARGETS update
+ # Install handled below.
+ INSTALL_COMMAND ""
+ )
+endif ()
+
+if (CMAKE_HOST_UNIX)
+ set(LLVM_LINK_OR_COPY create_symlink)
+else ()
+ set(LLVM_LINK_OR_COPY copy)
+endif ()
+
+# Link the provided or just built spirv-dis and spirv-val binaries.
+if (SPIRV_DIS)
+ add_custom_target(spirv-dis
+ COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${SPIRV_DIS}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-dis")
+else ()
+ add_custom_target(spirv-dis
+ COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${BINARY_DIR}/tools/spirv-dis" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-dis"
+ DEPENDS SPIRVTools
+ )
+endif ()
+
+if (SPIRV_VAL)
+ add_custom_target(spirv-val
+ COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${SPIRV_VAL}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-val")
+else ()
+ add_custom_target(spirv-val
+ COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${BINARY_DIR}/tools/spirv-val" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-val"
+ DEPENDS SPIRVTools
+ )
+endif ()
diff --git a/src/llvm-project/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp b/src/llvm-project/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
index b0b8013..e1041bd 100644
--- a/src/llvm-project/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
+++ b/src/llvm-project/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
@@ -10,8 +10,8 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Analysis/VectorUtils.h"
#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/VFABIDemangler.h"
using namespace llvm;
@@ -27,15 +27,16 @@
// present. We need to make sure we can even invoke
// `getOrInsertFunction` because such method asserts on strings with
// zeroes.
- if (!MangledName.empty() && MangledName.find_first_of(0) == StringRef::npos)
- M->getOrInsertFunction(
- MangledName,
- FunctionType::get(Type::getVoidTy(M->getContext()), false));
- const auto Info = VFABI::tryDemangleForVFABI(MangledName, *M);
+ // TODO: What is this actually testing? That we don't crash?
+ if (!MangledName.empty() && MangledName.find_first_of(0) == StringRef::npos) {
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(M->getContext()), false);
+ const auto Info = VFABI::tryDemangleForVFABI(MangledName, FTy);
- // Do not optimize away the return value. Inspired by
- // https://github.com/google/benchmark/blob/main/include/benchmark/benchmark.h#L307-L345
- asm volatile("" : : "r,m"(Info) : "memory");
+ // Do not optimize away the return value. Inspired by
+ // https://github.com/google/benchmark/blob/main/include/benchmark/benchmark.h#L307-L345
+ asm volatile("" : : "r,m"(Info) : "memory");
+ }
return 0;
}
diff --git a/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp b/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp
index ba1f54d..b7f5356 100644
--- a/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp
+++ b/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp
@@ -78,9 +78,9 @@
std::string Preprocessed;
while (!Buf.empty()) {
- if (Buf.startswith("[[")) {
+ if (Buf.starts_with("[[")) {
size_t I = Buf.find_first_of("[]", 2);
- if (Buf.substr(I).startswith("]]")) {
+ if (Buf.substr(I).starts_with("]]")) {
StringRef MacroExpr = Buf.substr(2, I - 2);
StringRef Macro;
StringRef Default;
@@ -92,7 +92,7 @@
std::optional<StringRef> Value;
if (It != Defines.end())
Value = It->second;
- else if (!Default.empty() || MacroExpr.endswith("="))
+ else if (!Default.empty() || MacroExpr.ends_with("="))
Value = Default;
if (Value) {