Importing rustc-1.70.0
Test: ./build.py --lto=thin
Change-Id: I34045ec5a79462afe9900f38a66f9783d4055a18
diff --git a/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt b/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt
index eea3e23..6df49d7 100644
--- a/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/bugpoint-passes/CMakeLists.txt
@@ -11,7 +11,7 @@
endif()
if(WIN32 OR CYGWIN)
- set(LLVM_LINK_COMPONENTS Core)
+ set(LLVM_LINK_COMPONENTS Core Support)
endif()
add_llvm_library( BugpointPasses MODULE BUILDTREE_ONLY
diff --git a/src/llvm-project/llvm/tools/bugpoint-passes/TestPasses.cpp b/src/llvm-project/llvm/tools/bugpoint-passes/TestPasses.cpp
index 1e66953..aad1377 100644
--- a/src/llvm-project/llvm/tools/bugpoint-passes/TestPasses.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint-passes/TestPasses.cpp
@@ -68,7 +68,7 @@
if (CallInst *CI = dyn_cast<CallInst>(I)) {
if (!CI->use_empty())
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
- CI->getParent()->getInstList().erase(CI);
+ CI->eraseFromParent();
break;
}
return false;
diff --git a/src/llvm-project/llvm/tools/bugpoint/CMakeLists.txt b/src/llvm-project/llvm/tools/bugpoint/CMakeLists.txt
index d64481df..b0e7191 100644
--- a/src/llvm-project/llvm/tools/bugpoint/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/bugpoint/CMakeLists.txt
@@ -18,6 +18,7 @@
ScalarOpts
Support
Target
+ TargetParser
TransformUtils
Vectorize
)
diff --git a/src/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp b/src/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp
index 9912f59..c90e1af 100644
--- a/src/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp
@@ -484,7 +484,7 @@
BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType()));
// Replace the old terminator instruction.
- BB.getInstList().pop_back();
+ BB.back().eraseFromParent();
new UnreachableInst(BB.getContext(), &BB);
}
}
@@ -791,7 +791,7 @@
!Inst.isEHPad() && !Inst.getType()->isTokenTy() &&
!Inst.isSwiftError()) {
if (!Inst.getType()->isVoidTy())
- Inst.replaceAllUsesWith(UndefValue::get(Inst.getType()));
+ Inst.replaceAllUsesWith(PoisonValue::get(Inst.getType()));
Inst.eraseFromParent();
}
}
@@ -1338,7 +1338,7 @@
// contribute to the crash, bisect the operands of the remaining ones
std::vector<const MDNode *> NamedMDOps;
for (auto &NamedMD : BD.getProgram().named_metadata())
- for (auto op : NamedMD.operands())
+ for (auto *op : NamedMD.operands())
NamedMDOps.push_back(op);
Expected<bool> Result =
ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps);
diff --git a/src/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp b/src/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp
index 7a75cb90..5047aa3 100644
--- a/src/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp
@@ -105,7 +105,7 @@
TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType()));
// Remove the instruction from the program.
- TheInst->getParent()->getInstList().erase(TheInst);
+ TheInst->eraseFromParent();
// Spiff up the output a little bit.
std::vector<std::string> Passes;
diff --git a/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp b/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp
index d425a8c..1197528 100644
--- a/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp
@@ -232,7 +232,8 @@
<< " " << Args[i];
errs() << "\n";);
- Optional<StringRef> Redirects[3] = {None, None, None};
+ std::optional<StringRef> Redirects[3] = {std::nullopt, std::nullopt,
+ std::nullopt};
// Redirect stdout and stderr to nowhere if SilencePasses is given.
if (SilencePasses) {
Redirects[1] = "";
@@ -240,7 +241,7 @@
}
std::string ErrMsg;
- int result = sys::ExecuteAndWait(Prog, Args, None, Redirects, Timeout,
+ int result = sys::ExecuteAndWait(Prog, Args, std::nullopt, Redirects, Timeout,
MemoryLimit, &ErrMsg);
// If we are supposed to delete the bitcode file or if the passes crashed,
diff --git a/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp b/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
index d3111e5..352588f 100644
--- a/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
@@ -58,9 +58,9 @@
unsigned NumSeconds = 0,
unsigned MemoryLimit = 0,
std::string *ErrMsg = nullptr) {
- Optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
- return sys::ExecuteAndWait(ProgramPath, Args, None, Redirects, NumSeconds,
- MemoryLimit, ErrMsg);
+ std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
+ return sys::ExecuteAndWait(ProgramPath, Args, std::nullopt, Redirects,
+ NumSeconds, MemoryLimit, ErrMsg);
}
/// RunProgramRemotelyWithTimeout - This function runs the given program
@@ -73,11 +73,11 @@
StringRef RemoteClientPath, ArrayRef<StringRef> Args, StringRef StdInFile,
StringRef StdOutFile, StringRef StdErrFile, unsigned NumSeconds = 0,
unsigned MemoryLimit = 0) {
- Optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
+ std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
// Run the program remotely with the remote client
- int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, None, Redirects,
- NumSeconds, MemoryLimit);
+ int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, std::nullopt,
+ Redirects, NumSeconds, MemoryLimit);
// Has the remote client fail?
if (255 == ReturnCode) {
diff --git a/src/llvm-project/llvm/tools/bugpoint/bugpoint.cpp b/src/llvm-project/llvm/tools/bugpoint/bugpoint.cpp
index 4dece12..0305f64 100644
--- a/src/llvm-project/llvm/tools/bugpoint/bugpoint.cpp
+++ b/src/llvm-project/llvm/tools/bugpoint/bugpoint.cpp
@@ -143,14 +143,11 @@
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
- initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
- initializeAggressiveInstCombine(Registry);
- initializeInstrumentation(Registry);
initializeTarget(Registry);
if (std::getenv("bar") == (char*) -1) {
diff --git a/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp b/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp
index d16e1d5..d8293f7 100644
--- a/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/BinaryHolder.cpp
@@ -173,7 +173,7 @@
// Try the cache first.
std::lock_guard<std::mutex> Lock(MemberCacheMutex);
if (MemberCache.count(Key))
- return *MemberCache[Key].get();
+ return *MemberCache[Key];
// Create a new ObjectEntry, but don't add it to the cache yet. Loading of
// the archive members might fail and we don't want to lock the whole archive
diff --git a/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt b/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt
index 38028cd..ae92e3f 100644
--- a/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt
@@ -9,6 +9,7 @@
AsmPrinter
DebugInfoDWARF
DWARFLinker
+ DWARFLinkerParallel
MC
Object
CodeGen
@@ -16,6 +17,7 @@
Remarks
Support
Target
+ TargetParser
)
add_llvm_tool(dsymutil
@@ -33,7 +35,6 @@
intrinsics_gen
${tablegen_deps}
DsymutilTableGen
- GENERATE_DRIVER
)
if(APPLE)
diff --git a/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp b/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp
index 79b6cb2..68c26bc 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/DebugMap.cpp
@@ -8,7 +8,6 @@
#include "DebugMap.h"
#include "BinaryHolder.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -28,6 +27,7 @@
#include <cinttypes>
#include <cstdint>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -43,7 +43,8 @@
uint8_t Type)
: Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}
-bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress,
+bool DebugMapObject::addSymbol(StringRef Name,
+ std::optional<uint64_t> ObjectAddress,
uint64_t LinkedAddress, uint32_t Size) {
auto InsertResult = Symbols.insert(
std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
@@ -277,7 +278,7 @@
dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
for (auto &Entry : Entries) {
auto &Mapping = Entry.second;
- Optional<uint64_t> ObjAddress;
+ std::optional<uint64_t> ObjAddress;
if (Mapping.ObjectAddress)
ObjAddress = *Mapping.ObjectAddress;
auto AddressIt = SymbolAddresses.find(Entry.first);
diff --git a/src/llvm-project/llvm/tools/dsymutil/DebugMap.h b/src/llvm-project/llvm/tools/dsymutil/DebugMap.h
index e4fbaa8..4854f41be 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DebugMap.h
+++ b/src/llvm-project/llvm/tools/dsymutil/DebugMap.h
@@ -22,7 +22,6 @@
#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
@@ -35,6 +34,7 @@
#include <cstddef>
#include <cstdint>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -135,11 +135,11 @@
class DebugMapObject {
public:
struct SymbolMapping {
- Optional<yaml::Hex64> ObjectAddress;
+ std::optional<yaml::Hex64> ObjectAddress;
yaml::Hex64 BinaryAddress;
yaml::Hex32 Size;
- SymbolMapping(Optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
+ SymbolMapping(std::optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
uint32_t Size)
: BinaryAddress(BinaryAddress), Size(Size) {
if (ObjectAddr)
@@ -156,7 +156,7 @@
/// Adds a symbol mapping to this DebugMapObject.
/// \returns false if the symbol was already registered. The request
/// is discarded in this case.
- bool addSymbol(StringRef SymName, Optional<uint64_t> ObjectAddress,
+ bool addSymbol(StringRef SymName, std::optional<uint64_t> ObjectAddress,
uint64_t LinkedAddress, uint32_t Size);
/// Lookup a symbol mapping.
diff --git a/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index 5f43680..8df95f5 100644
--- a/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -18,8 +18,6 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -94,6 +92,7 @@
#include <limits>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <system_error>
#include <tuple>
@@ -410,7 +409,7 @@
}
auto CalculateAddressOfSymbolInDwarfSegment =
- [&]() -> llvm::Optional<int64_t> {
+ [&]() -> std::optional<int64_t> {
auto Symbol = It->getSymbol();
auto SymbolAbsoluteAddress = Symbol->getAddress();
if (!SymbolAbsoluteAddress)
@@ -446,7 +445,7 @@
bool ShouldSubtractDwarfVM = false;
// For the second symbol there are two possibilities.
- llvm::Optional<int64_t> SecondSymbolAddress;
+ std::optional<int64_t> SecondSymbolAddress;
auto Sym = It->getSymbol();
if (Sym != MO->symbol_end()) {
Expected<StringRef> SymbolName = Sym->getName();
@@ -506,7 +505,7 @@
if (auto *MO = dyn_cast<llvm::object::MachOObjectFile>(OF->getBinary())) {
// Collect the swift reflection sections before emitting them. This is
// done so we control the order they're emitted.
- std::array<Optional<object::SectionRef>,
+ std::array<std::optional<object::SectionRef>,
Swift5ReflectionSectionKind::last + 1>
SwiftSections;
for (auto &Section : MO->sections()) {
@@ -543,7 +542,7 @@
// place.
SectionToOffsetInDwarf[SectionKind] += Section.getSize();
Streamer->emitSwiftReflectionSection(SectionKind, *SectionContents,
- Section.getAlignment(),
+ Section.getAlignment().value(),
Section.getSize());
}
}
@@ -578,7 +577,6 @@
GeneralLinker.setNoODR(Options.NoODR);
GeneralLinker.setUpdate(Options.Update);
GeneralLinker.setNumThreads(Options.Threads);
- GeneralLinker.setAccelTableKind(Options.TheAccelTableKind);
GeneralLinker.setPrependPath(Options.PrependPath);
GeneralLinker.setKeepFunctionForStatic(Options.KeepFunctionForStatic);
if (Options.Translator)
@@ -591,58 +589,58 @@
[&](const Twine &Error, StringRef Context, const DWARFDie *) {
error(Error, Context);
});
- GeneralLinker.setObjFileLoader(
- [&DebugMap, &RL, this](StringRef ContainerName,
- StringRef Path) -> ErrorOr<DWARFFile &> {
- auto &Obj = DebugMap.addDebugMapObject(
- Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
+ objFileLoader Loader = [&DebugMap, &RL,
+ this](StringRef ContainerName,
+ StringRef Path) -> ErrorOr<DWARFFile &> {
+ auto &Obj = DebugMap.addDebugMapObject(
+ Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
- if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
- return *ErrorOrObj;
- } 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(")");
+ if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
+ return *ErrorOrObj;
+ } 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(")");
- if (IsClangModule) {
- StringRef ModuleCacheDir = sys::path::parent_path(Path);
- if (sys::fs::exists(ModuleCacheDir)) {
- // If the module's parent directory exists, we assume that the
- // module cache has expired and was pruned by clang. A more
- // adventurous dsymutil would invoke clang to rebuild the module
- // now.
- if (!ModuleCacheHintDisplayed) {
- WithColor::note()
- << "The clang module cache may have expired since "
- "this object file was built. Rebuilding the "
- "object file will rebuild the module cache.\n";
- ModuleCacheHintDisplayed = true;
- }
- } else if (IsArchive) {
- // If the module cache directory doesn't exist at all and the
- // object file is inside a static library, we assume that the
- // static library was built on a different machine. We don't want
- // to discourage module debugging for convenience libraries within
- // a project though.
- if (!ArchiveHintDisplayed) {
- WithColor::note()
- << "Linking a static library that was built with "
- "-gmodules, but the module cache was not found. "
- "Redistributable static libraries should never be "
- "built with module debugging enabled. The debug "
- "experience will be degraded due to incomplete "
- "debug information.\n";
- ArchiveHintDisplayed = true;
- }
- }
+ if (IsClangModule) {
+ StringRef ModuleCacheDir = sys::path::parent_path(Path);
+ if (sys::fs::exists(ModuleCacheDir)) {
+ // If the module's parent directory exists, we assume that the
+ // module cache has expired and was pruned by clang. A more
+ // adventurous dsymutil would invoke clang to rebuild the module
+ // now.
+ if (!ModuleCacheHintDisplayed) {
+ WithColor::note()
+ << "The clang module cache may have expired since "
+ "this object file was built. Rebuilding the "
+ "object file will rebuild the module cache.\n";
+ ModuleCacheHintDisplayed = true;
}
-
- return ErrorOrObj.getError();
+ } else if (IsArchive) {
+ // If the module cache directory doesn't exist at all and the
+ // object file is inside a static library, we assume that the
+ // static library was built on a different machine. We don't want
+ // to discourage module debugging for convenience libraries within
+ // a project though.
+ if (!ArchiveHintDisplayed) {
+ WithColor::note()
+ << "Linking a static library that was built with "
+ "-gmodules, but the module cache was not found. "
+ "Redistributable static libraries should never be "
+ "built with module debugging enabled. The debug "
+ "experience will be degraded due to incomplete "
+ "debug information.\n";
+ ArchiveHintDisplayed = true;
+ }
}
+ }
- llvm_unreachable("Unhandled DebugMap object");
- });
+ return ErrorOrObj.getError();
+ }
+
+ llvm_unreachable("Unhandled DebugMap object");
+ };
GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
bool ReflectionSectionsPresentInBinary = false;
// If there is no output specified, no point in checking the binary for swift5
@@ -661,6 +659,12 @@
SectionToOffsetInDwarf, RelocationsToApply);
}
+ uint16_t MaxDWARFVersion = 0;
+ std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
+ [&MaxDWARFVersion](const DWARFUnit &Unit) {
+ MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
+ };
+
for (const auto &Obj : Map.objects()) {
// N_AST objects (swiftmodule files) should get dumped directly into the
// appropriate DWARF section.
@@ -702,8 +706,9 @@
continue;
}
+
if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
- GeneralLinker.addObjectFile(*ErrorOrObj);
+ GeneralLinker.addObjectFile(*ErrorOrObj, Loader, OnCUDieLoaded);
else {
ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
Obj->getObjectFilename(), nullptr, nullptr,
@@ -712,6 +717,34 @@
}
}
+ // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
+ if (MaxDWARFVersion == 0)
+ MaxDWARFVersion = 3;
+
+ if (Error E = GeneralLinker.setTargetDWARFVersion(MaxDWARFVersion))
+ return error(toString(std::move(E)));
+
+ switch (Options.TheAccelTableKind) {
+ case DsymutilAccelTableKind::Apple:
+ GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple);
+ break;
+ case DsymutilAccelTableKind::Dwarf:
+ GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames);
+ break;
+ case DsymutilAccelTableKind::Pub:
+ GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Pub);
+ break;
+ case DsymutilAccelTableKind::Default:
+ if (MaxDWARFVersion >= 5)
+ GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames);
+ else
+ GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple);
+ break;
+ case DsymutilAccelTableKind::None:
+ // Nothing to do.
+ break;
+ }
+
// link debug info for loaded object files.
if (Error E = GeneralLinker.link())
return error(toString(std::move(E)));
@@ -945,7 +978,7 @@
const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
- Optional<uint32_t> LocationIdx =
+ std::optional<uint32_t> LocationIdx =
Abbrev->findAttributeIndex(dwarf::DW_AT_location);
if (!LocationIdx)
return false;
@@ -964,7 +997,8 @@
const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
- Optional<uint32_t> LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
+ std::optional<uint32_t> LowPcIdx =
+ Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
if (!LowPcIdx)
return false;
@@ -980,8 +1014,8 @@
}
if (Form == dwarf::DW_FORM_addrx) {
- Optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
- if (Optional<uint64_t> AddrOffsetSectionBase =
+ std::optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
+ if (std::optional<uint64_t> AddrOffsetSectionBase =
DIE.getDwarfUnit()->getAddrOffsetSectionBase()) {
uint64_t StartOffset = *AddrOffsetSectionBase + AddrValue->getRawUValue();
uint64_t EndOffset =
diff --git a/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h b/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h
index 03b9a64..f08d923 100644
--- a/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h
+++ b/src/llvm-project/llvm/tools/dsymutil/LinkUtils.h
@@ -23,6 +23,14 @@
namespace llvm {
namespace dsymutil {
+enum class DsymutilAccelTableKind : uint8_t {
+ None,
+ Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc.
+ Dwarf, ///< DWARF v5 .debug_names.
+ Default, ///< Dwarf for DWARF5 or later, Apple otherwise.
+ Pub, ///< .debug_pubnames, .debug_pubtypes
+};
+
struct LinkOptions {
/// Verbosity
bool Verbose = false;
@@ -56,7 +64,7 @@
OutputFileType FileType = OutputFileType::Object;
/// The accelerator table kind
- DwarfLinkerAccelTableKind TheAccelTableKind;
+ DsymutilAccelTableKind TheAccelTableKind;
/// -oso-prepend-path
std::string PrependPath;
@@ -65,7 +73,7 @@
std::map<std::string, std::string> ObjectPrefixMap;
/// The Resources directory in the .dSYM bundle.
- Optional<std::string> ResourceDir;
+ std::optional<std::string> ResourceDir;
/// Symbol map translator.
SymbolMapTranslator Translator;
diff --git a/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp b/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp
index 955272b..2f391c5 100644
--- a/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/MachODebugMapParser.cpp
@@ -9,12 +9,12 @@
#include "BinaryHolder.h"
#include "DebugMap.h"
#include "MachOUtils.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
#include <vector>
namespace {
@@ -59,10 +59,10 @@
std::vector<std::string> CommonSymbols;
/// Map of the currently processed object file symbol addresses.
- StringMap<Optional<uint64_t>> CurrentObjectAddresses;
+ StringMap<std::optional<uint64_t>> CurrentObjectAddresses;
/// Lazily computed map of symbols aliased to the processed object file.
- StringMap<Optional<uint64_t>> CurrentObjectAliasMap;
+ StringMap<std::optional<uint64_t>> CurrentObjectAliasMap;
/// If CurrentObjectAliasMap has been computed for a given address.
SmallSet<uint64_t, 4> SeenAliasValues;
@@ -151,7 +151,8 @@
// The main binary doesn't have an address for the given symbol.
continue;
}
- if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/,
+ if (!CurrentDebugMapObject->addSymbol(CommonSymbol,
+ std::nullopt /*ObjectAddress*/,
CommonAddr, 0 /*size*/)) {
// The symbol is already present.
continue;
@@ -533,9 +534,9 @@
// in the DebugMap, leave it unassigned for these symbols.
uint32_t Flags = cantFail(Sym.getFlags());
if (Flags & SymbolRef::SF_Absolute) {
- CurrentObjectAddresses[*Name] = None;
+ CurrentObjectAddresses[*Name] = std::nullopt;
} else if (Flags & SymbolRef::SF_Common) {
- CurrentObjectAddresses[*Name] = None;
+ CurrentObjectAddresses[*Name] = std::nullopt;
CommonSymbols.push_back(std::string(*Name));
} else {
CurrentObjectAddresses[*Name] = Addr;
diff --git a/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp b/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp
index 3bf455e..2d3437e 100644
--- a/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/MachOUtils.cpp
@@ -56,7 +56,7 @@
}
static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
- auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath));
+ auto Path = sys::findProgramByName("lipo", ArrayRef(SDKPath));
if (!Path)
Path = sys::findProgramByName("lipo");
@@ -66,7 +66,8 @@
}
std::string ErrMsg;
- int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg);
+ int result =
+ sys::ExecuteAndWait(*Path, Args, std::nullopt, {}, 0, 0, &ErrMsg);
if (result) {
WithColor::error() << "lipo: " << ErrMsg << "\n";
return false;
@@ -317,10 +318,10 @@
if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec))
continue;
- unsigned Align = Sec->getAlignment();
- if (Align > 1) {
- VMAddr = alignTo(VMAddr, Align);
- FileOffset = alignTo(FileOffset, Align);
+ Align Alignment = Sec->getAlign();
+ if (Alignment > 1) {
+ 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.");
@@ -477,7 +478,7 @@
continue;
if (uint64_t Size = Layout.getSectionFileSize(Sec)) {
- DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment());
+ DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlign());
DwarfSegmentSize += Size;
++NumDwarfSections;
}
@@ -617,7 +618,7 @@
continue;
uint64_t Pos = OutFile.tell();
- OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos);
+ OutFile.write_zeros(alignTo(Pos, Sec.getAlign()) - Pos);
MCAsm.writeSectionData(OutFile, &Sec, Layout);
}
diff --git a/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp b/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp
index 2e28859..dda5557 100644
--- a/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/Reproducer.cpp
@@ -20,6 +20,7 @@
} else {
EC = sys::fs::createUniqueDirectory("dsymutil", Root);
}
+ sys::fs::make_absolute(Root);
return EC ? "" : std::string(Root);
}
diff --git a/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp b/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp
index 0ebdcc1..75876a8 100644
--- a/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp
+++ b/src/llvm-project/llvm/tools/dsymutil/dsymutil.cpp
@@ -63,11 +63,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "Options.inc"
#undef PREFIX
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -79,9 +82,9 @@
#undef OPTION
};
-class DsymutilOptTable : public opt::OptTable {
+class DsymutilOptTable : public opt::GenericOptTable {
public:
- DsymutilOptTable() : OptTable(InfoTable) {}
+ DsymutilOptTable() : opt::GenericOptTable(InfoTable) {}
};
} // namespace
@@ -206,26 +209,26 @@
return Error::success();
}
-static Expected<DwarfLinkerAccelTableKind>
+static Expected<DsymutilAccelTableKind>
getAccelTableKind(opt::InputArgList &Args) {
if (opt::Arg *Accelerator = Args.getLastArg(OPT_accelerator)) {
StringRef S = Accelerator->getValue();
if (S == "Apple")
- return DwarfLinkerAccelTableKind::Apple;
+ return DsymutilAccelTableKind::Apple;
if (S == "Dwarf")
- return DwarfLinkerAccelTableKind::Dwarf;
+ return DsymutilAccelTableKind::Dwarf;
if (S == "Pub")
- return DwarfLinkerAccelTableKind::Pub;
+ return DsymutilAccelTableKind::Pub;
if (S == "Default")
- return DwarfLinkerAccelTableKind::Default;
+ return DsymutilAccelTableKind::Default;
if (S == "None")
- return DwarfLinkerAccelTableKind::None;
+ return DsymutilAccelTableKind::None;
return make_error<StringError>("invalid accelerator type specified: '" + S +
"'. Supported values are 'Apple', "
"'Dwarf', 'Pub', 'Default' and 'None'.",
inconvertibleErrorCode());
}
- return DwarfLinkerAccelTableKind::Default;
+ return DsymutilAccelTableKind::Default;
}
static Expected<ReproducerMode> getReproducerMode(opt::InputArgList &Args) {
@@ -310,7 +313,7 @@
}
}
- if (Expected<DwarfLinkerAccelTableKind> AccelKind = getAccelTableKind(Args)) {
+ if (Expected<DsymutilAccelTableKind> AccelKind = getAccelTableKind(Args)) {
Options.LinkOpts.TheAccelTableKind = *AccelKind;
} else {
return AccelKind.takeError();
@@ -485,12 +488,13 @@
namespace {
struct OutputLocation {
- OutputLocation(std::string DWARFFile, Optional<std::string> ResourceDir = {})
+ OutputLocation(std::string DWARFFile,
+ std::optional<std::string> ResourceDir = {})
: DWARFFile(DWARFFile), ResourceDir(ResourceDir) {}
/// This method is a workaround for older compilers.
- Optional<std::string> getResourceDir() const { return ResourceDir; }
+ std::optional<std::string> getResourceDir() const { return ResourceDir; }
std::string DWARFFile;
- Optional<std::string> ResourceDir;
+ std::optional<std::string> ResourceDir;
};
} // namespace
@@ -546,14 +550,14 @@
return OutputLocation(std::string(Path.str()), ResourceDir);
}
-int dsymutil_main(int argc, char **argv) {
+int main(int argc, char **argv) {
InitLLVM X(argc, argv);
// Parse arguments.
DsymutilOptTable T;
unsigned MAI;
unsigned MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc - 1);
+ ArrayRef<const char *> ArgsArr = ArrayRef(argv + 1, argc - 1);
opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
void *P = (void *)(intptr_t)getOutputFileName;
@@ -798,7 +802,7 @@
break;
FileOffset += stat->getSize();
if (FileOffset > UINT32_MAX) {
- WithColor::error() << "the univesral binary has a slice with an "
+ WithColor::error() << "the universal binary has a slice with an "
"offset exceeds 4GB and will produce an invalid Mach-O file.";
return EXIT_FAILURE;
}
diff --git a/src/llvm-project/llvm/tools/dxil-dis/CMakeLists.txt b/src/llvm-project/llvm/tools/dxil-dis/CMakeLists.txt
index 2859318..9addf10 100644
--- a/src/llvm-project/llvm/tools/dxil-dis/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/dxil-dis/CMakeLists.txt
@@ -17,7 +17,7 @@
if (DXIL_DIS)
add_custom_target(dxil-dis
- COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${DXIL_DIS}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/dxil-dis")
+ COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${DXIL_DIS}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/dxil-dis${CMAKE_EXECUTABLE_SUFFIX}")
return()
endif ()
diff --git a/src/llvm-project/llvm/tools/gold/CMakeLists.txt b/src/llvm-project/llvm/tools/gold/CMakeLists.txt
index 72f7655..58b3238 100644
--- a/src/llvm-project/llvm/tools/gold/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/gold/CMakeLists.txt
@@ -9,6 +9,7 @@
LTO
BitWriter
IPO
+ TargetParser
)
add_llvm_library(LLVMgold MODULE
diff --git a/src/llvm-project/llvm/tools/gold/gold-plugin.cpp b/src/llvm-project/llvm/tools/gold/gold-plugin.cpp
index f1b457b..939dbaf 100644
--- a/src/llvm-project/llvm/tools/gold/gold-plugin.cpp
+++ b/src/llvm-project/llvm/tools/gold/gold-plugin.cpp
@@ -121,7 +121,7 @@
static ld_plugin_get_view get_view = nullptr;
static bool IsExecutable = false;
static bool SplitSections = true;
-static Optional<Reloc::Model> RelocationModel = None;
+static std::optional<Reloc::Model> RelocationModel;
static std::string output_name = "";
static std::list<claimed_file> Modules;
static DenseMap<int, void *> FDToLeaderHandle;
@@ -215,7 +215,7 @@
static std::string RemarksFilename;
static std::string RemarksPasses;
static bool RemarksWithHotness = false;
- static Optional<uint64_t> RemarksHotnessThreshold = 0;
+ static std::optional<uint64_t> RemarksHotnessThreshold = 0;
static std::string RemarksFormat;
// Context sensitive PGO options.
@@ -722,8 +722,8 @@
// Returns true if S is valid as a C language identifier.
static bool isValidCIdentifier(StringRef S) {
return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
- std::all_of(S.begin() + 1, S.end(),
- [](char C) { return C == '_' || isAlnum(C); });
+ llvm::all_of(llvm::drop_begin(S),
+ [](char C) { return C == '_' || isAlnum(C); });
}
static bool isUndefined(ld_plugin_symbol &Sym) {
@@ -846,20 +846,6 @@
return FD;
}
-static CodeGenOpt::Level getCGOptLevel() {
- switch (options::OptLevel) {
- case 0:
- return CodeGenOpt::None;
- case 1:
- return CodeGenOpt::Less;
- case 2:
- return CodeGenOpt::Default;
- case 3:
- return CodeGenOpt::Aggressive;
- }
- llvm_unreachable("Invalid optimization level");
-}
-
/// Parse the thinlto_prefix_replace option into the \p OldPrefix and
/// \p NewPrefix strings, if it was specified.
static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
@@ -896,7 +882,10 @@
Conf.MAttrs = codegen::getMAttrs();
Conf.RelocModel = RelocationModel;
Conf.CodeModel = codegen::getExplicitCodeModel();
- Conf.CGOptLevel = getCGOptLevel();
+ std::optional<CodeGenOpt::Level> CGOptLevelOrNone =
+ CodeGenOpt::getLevel(options::OptLevel);
+ assert(CGOptLevelOrNone && "Invalid optimization level");
+ Conf.CGOptLevel = *CGOptLevelOrNone;
Conf.DisableVerify = options::DisableVerify;
Conf.OptLevel = options::OptLevel;
Conf.PTO.LoopVectorization = options::OptLevel > 1;
@@ -1091,7 +1080,9 @@
size_t MaxTasks = Lto->getMaxTasks();
std::vector<std::pair<SmallString<128>, bool>> Files(MaxTasks);
- auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
+ auto AddStream =
+ [&](size_t Task,
+ const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
Files[Task].second = !SaveTemps;
int FD = getOutputFileName(Filename, /* TempOutFile */ !SaveTemps,
Files[Task].first, Task);
@@ -1099,8 +1090,9 @@
std::make_unique<llvm::raw_fd_ostream>(FD, true));
};
- auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
- *AddStream(Task)->OS << MB->getBuffer();
+ auto AddBuffer = [&](size_t Task, const Twine &moduleName,
+ std::unique_ptr<MemoryBuffer> MB) {
+ *AddStream(Task, moduleName)->OS << MB->getBuffer();
};
FileCache Cache;
diff --git a/src/llvm-project/llvm/tools/llc/CMakeLists.txt b/src/llvm-project/llvm/tools/llc/CMakeLists.txt
index f0bc582..d283ebe 100644
--- a/src/llvm-project/llvm/tools/llc/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llc/CMakeLists.txt
@@ -16,6 +16,7 @@
SelectionDAG
Support
Target
+ TargetParser
TransformUtils
Vectorize
)
diff --git a/src/llvm-project/llvm/tools/llc/llc.cpp b/src/llvm-project/llvm/tools/llc/llc.cpp
index f084ee2..f2dae67 100644
--- a/src/llvm-project/llvm/tools/llc/llc.cpp
+++ b/src/llvm-project/llvm/tools/llc/llc.cpp
@@ -28,7 +28,6 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
-#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/LegacyPassManager.h"
@@ -57,6 +56,7 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <memory>
+#include <optional>
using namespace llvm;
static codegen::RegisterCodeGenFlags CGF;
@@ -120,7 +120,7 @@
OptLevel("O",
cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
"(default = '-O2')"),
- cl::Prefix, cl::init(' '));
+ cl::Prefix, cl::init('2'));
static cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
@@ -166,7 +166,7 @@
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
-static cl::opt<Optional<uint64_t>, false, remarks::HotnessThresholdParser>
+static cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
RemarksHotnessThreshold(
"pass-remarks-hotness-threshold",
cl::desc("Minimum profile count required for "
@@ -374,6 +374,8 @@
// Initialize debugging passes.
initializeScavengerTestPass(*Registry);
+ // Register the Target and CPU printer for --version.
+ cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
@@ -467,19 +469,15 @@
};
auto MAttrs = codegen::getMAttrs();
- bool SkipModule = codegen::getMCPU() == "help" ||
- (!MAttrs.empty() && MAttrs.front() == "help");
+ bool SkipModule =
+ CPUStr == "help" || (!MAttrs.empty() && MAttrs.front() == "help");
- CodeGenOpt::Level OLvl = CodeGenOpt::Default;
- switch (OptLevel) {
- default:
+ CodeGenOpt::Level OLvl;
+ if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
+ OLvl = *Level;
+ } else {
WithColor::error(errs(), argv[0]) << "invalid optimization level.\n";
return 1;
- case ' ': break;
- case '0': OLvl = CodeGenOpt::None; break;
- case '1': OLvl = CodeGenOpt::Less; break;
- case '2': OLvl = CodeGenOpt::Default; break;
- case '3': OLvl = CodeGenOpt::Aggressive; break;
}
// Parse 'none' or '$major.$minor'. Disallow -binutils-version=0 because we
@@ -520,16 +518,16 @@
}
};
- Optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
- Optional<CodeModel::Model> CM = codegen::getExplicitCodeModel();
+ std::optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
+ std::optional<CodeModel::Model> CM = codegen::getExplicitCodeModel();
const Target *TheTarget = nullptr;
std::unique_ptr<TargetMachine> Target;
// If user just wants to list available options, skip module loading
if (!SkipModule) {
- auto SetDataLayout =
- [&](StringRef DataLayoutTargetTriple) -> Optional<std::string> {
+ auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
+ StringRef OldDLStr) -> std::optional<std::string> {
// If we are supposed to override the target triple, do so now.
std::string IRTargetTriple = DataLayoutTargetTriple.str();
if (!TargetTriple.empty())
@@ -566,7 +564,8 @@
if (MIR)
M = MIR->parseIRModule(SetDataLayout);
} else {
- M = parseIRFile(InputFilename, Err, Context, SetDataLayout);
+ M = parseIRFile(InputFilename, Err, Context,
+ ParserCallbacks(SetDataLayout));
}
if (!M) {
Err.print(argv[0], WithColor::error(errs(), argv[0]));
@@ -575,9 +574,9 @@
if (!TargetTriple.empty())
M->setTargetTriple(Triple::normalize(TargetTriple));
- Optional<CodeModel::Model> CM_IR = M->getCodeModel();
+ std::optional<CodeModel::Model> CM_IR = M->getCodeModel();
if (!CM && CM_IR)
- Target->setCodeModel(CM_IR.value());
+ Target->setCodeModel(*CM_IR);
} else {
TheTriple = Triple(Triple::normalize(TargetTriple));
if (TheTriple.getTriple().empty())
diff --git a/src/llvm-project/llvm/tools/lli/CMakeLists.txt b/src/llvm-project/llvm/tools/lli/CMakeLists.txt
index 90797cc..3b3cf91 100644
--- a/src/llvm-project/llvm/tools/lli/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/lli/CMakeLists.txt
@@ -20,6 +20,7 @@
SelectionDAG
Support
Target
+ TargetParser
TransformUtils
native
)
diff --git a/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h b/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h
index 99a545e..f1de7a1 100644
--- a/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h
+++ b/src/llvm-project/llvm/tools/lli/ForwardingMemoryManager.h
@@ -43,10 +43,10 @@
IsReadOnly);
}
- void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
- uintptr_t RODataSize, uint32_t RODataAlign,
+ void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign,
+ uintptr_t RODataSize, Align RODataAlign,
uintptr_t RWDataSize,
- uint32_t RWDataAlign) override {
+ Align RWDataAlign) override {
MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign,
RWDataSize, RWDataAlign);
}
diff --git a/src/llvm-project/llvm/tools/lli/lli.cpp b/src/llvm-project/llvm/tools/lli/lli.cpp
index 3fd2a61..c9b77e2 100644
--- a/src/llvm-project/llvm/tools/lli/lli.cpp
+++ b/src/llvm-project/llvm/tools/lli/lli.cpp
@@ -70,6 +70,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
#include <cerrno>
+#include <optional>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
@@ -173,7 +174,7 @@
cl::opt<char> OptLevel("O",
cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
"(default = '-O2')"),
- cl::Prefix, cl::init(' '));
+ cl::Prefix, cl::init('2'));
cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
@@ -373,53 +374,6 @@
}
};
-class ORCPlatformSupport : public orc::LLJIT::PlatformSupport {
-public:
- ORCPlatformSupport(orc::LLJIT &J) : J(J) {}
-
- Error initialize(orc::JITDylib &JD) override {
- using llvm::orc::shared::SPSExecutorAddr;
- using llvm::orc::shared::SPSString;
- using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
- enum dlopen_mode : int32_t {
- ORC_RT_RTLD_LAZY = 0x1,
- ORC_RT_RTLD_NOW = 0x2,
- ORC_RT_RTLD_LOCAL = 0x4,
- ORC_RT_RTLD_GLOBAL = 0x8
- };
-
- if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlopen_wrapper")) {
- return J.getExecutionSession().callSPSWrapper<SPSDLOpenSig>(
- *WrapperAddr, DSOHandles[&JD], JD.getName(),
- int32_t(ORC_RT_RTLD_LAZY));
- } else
- return WrapperAddr.takeError();
- }
-
- Error deinitialize(orc::JITDylib &JD) override {
- using llvm::orc::shared::SPSExecutorAddr;
- using SPSDLCloseSig = int32_t(SPSExecutorAddr);
-
- if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlclose_wrapper")) {
- int32_t result;
- auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
- *WrapperAddr, result, DSOHandles[&JD]);
- if (E)
- return E;
- else if (result)
- return make_error<StringError>("dlclose failed",
- inconvertibleErrorCode());
- DSOHandles.erase(&JD);
- } else
- return WrapperAddr.takeError();
- return Error::success();
- }
-
-private:
- orc::LLJIT &J;
- DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
-};
-
// On Mingw and Cygwin, an external symbol named '__main' is called from the
// generated 'main' function to allow static initialization. To avoid linking
// problems with remote targets (because lli's remote target support does not
@@ -454,17 +408,10 @@
}
CodeGenOpt::Level getOptLevel() {
- switch (OptLevel) {
- default:
- WithColor::error(errs(), "lli") << "invalid optimization level.\n";
- exit(1);
- case '0': return CodeGenOpt::None;
- case '1': return CodeGenOpt::Less;
- case ' ':
- case '2': return CodeGenOpt::Default;
- case '3': return CodeGenOpt::Aggressive;
- }
- llvm_unreachable("Unrecognized opt level.");
+ if (auto Level = CodeGenOpt::parseLevel(OptLevel))
+ return *Level;
+ WithColor::error(errs(), "lli") << "invalid optimization level.\n";
+ exit(1);
}
[[noreturn]] static void reportError(SMDiagnostic Err, const char *ProgName) {
@@ -536,9 +483,9 @@
builder.setMCPU(codegen::getCPUStr());
builder.setMAttrs(codegen::getFeatureList());
if (auto RM = codegen::getExplicitRelocModel())
- builder.setRelocationModel(RM.value());
+ builder.setRelocationModel(*RM);
if (auto CM = codegen::getExplicitCodeModel())
- builder.setCodeModel(CM.value());
+ builder.setCodeModel(*CM);
builder.setErrorStr(&ErrorMsg);
builder.setEngineKind(ForceInterpreter
? EngineKind::Interpreter
@@ -891,8 +838,8 @@
// Get TargetTriple and DataLayout from the main module if they're explicitly
// set.
- Optional<Triple> TT;
- Optional<DataLayout> DL;
+ std::optional<Triple> TT;
+ std::optional<DataLayout> DL;
MainModule.withModuleDo([&](Module &M) {
if (!M.getTargetTriple().empty())
TT = Triple(M.getTargetTriple());
@@ -969,10 +916,7 @@
}
switch (P) {
case LLJITPlatform::ORC:
- Builder.setPlatformSetUp([](llvm::orc::LLJIT &J) -> llvm::Error {
- J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
- return Error::success();
- });
+ Builder.setPlatformSetUp(orc::setUpOrcPlatform);
break;
case LLJITPlatform::GenericIR:
// Nothing to do: LLJITBuilder will use this by default.
diff --git a/src/llvm-project/llvm/tools/llvm-ar/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-ar/CMakeLists.txt
index 166731e..19e3fad 100644
--- a/src/llvm-project/llvm/tools/llvm-ar/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-ar/CMakeLists.txt
@@ -8,6 +8,7 @@
LibDriver
Object
Support
+ TargetParser
TextAPI
)
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 4ffc5cf..12f3196 100644
--- a/src/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -875,8 +875,16 @@
if (Operation == QuickAppend || Members.empty())
return IA_AddOldMember;
- auto MI = find_if(
- Members, [Name](StringRef Path) { return comparePaths(Name, Path); });
+
+ auto MI = find_if(Members, [Name](StringRef Path) {
+ if (Thin && !sys::path::is_absolute(Path)) {
+ Expected<std::string> PathOrErr =
+ computeArchiveRelativePath(ArchiveName, Path);
+ return comparePaths(Name, PathOrErr ? *PathOrErr : Path);
+ } else {
+ return comparePaths(Name, Path);
+ }
+ });
if (MI == Members.end())
return IA_AddOldMember;
@@ -1218,7 +1226,7 @@
break;
case MRICommand::CreateThin:
Thin = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MRICommand::Create:
Create = true;
if (!ArchiveName.empty())
@@ -1322,7 +1330,7 @@
SmallVector<const char *, 0> Argv(argv + 1, argv + argc);
StringSaver Saver(Alloc);
- cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv);
+ cl::ExpandResponseFiles(Saver, getRspQuoting(ArrayRef(argv, argc)), Argv);
// Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if
// specified.
@@ -1465,11 +1473,11 @@
};
if (Is("dlltool"))
- return dlltoolDriverMain(makeArrayRef(argv, argc));
+ return dlltoolDriverMain(ArrayRef(argv, argc));
if (Is("ranlib"))
return ranlib_main(argc, argv);
if (Is("lib"))
- return libDriverMain(makeArrayRef(argv, argc));
+ return libDriverMain(ArrayRef(argv, argc));
if (Is("ar"))
return ar_main(argc, argv);
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 b777f72..ef1c50f 100644
--- a/src/llvm-project/llvm/tools/llvm-as/llvm-as.cpp
+++ b/src/llvm-project/llvm/tools/llvm-as/llvm-as.cpp
@@ -27,6 +27,7 @@
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include <memory>
+#include <optional>
using namespace llvm;
cl::OptionCategory AsCat("llvm-as Options");
@@ -120,9 +121,9 @@
// Parse the file now...
SMDiagnostic Err;
- auto SetDataLayout = [](StringRef) -> Optional<std::string> {
+ auto SetDataLayout = [](StringRef, StringRef) -> std::optional<std::string> {
if (ClDataLayout.empty())
- return None;
+ return std::nullopt;
return ClDataLayout;
};
ParsedModuleAndIndex ModuleAndIndex;
diff --git a/src/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/src/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index a238b0c..610b479 100644
--- a/src/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -27,7 +27,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/Optional.h"
#include "llvm/Bitcode/BitcodeAnalyzer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
@@ -36,6 +35,7 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <optional>
using namespace llvm;
static cl::OptionCategory BCAnalyzerCategory("BC Analyzer Options");
@@ -113,8 +113,9 @@
BlockInfoMB = ExitOnErr(openBitcodeFile(BlockInfoFilename));
BitcodeAnalyzer BA(MB->getBuffer(),
- BlockInfoMB ? Optional<StringRef>(BlockInfoMB->getBuffer())
- : None);
+ BlockInfoMB
+ ? std::optional<StringRef>(BlockInfoMB->getBuffer())
+ : std::nullopt);
BCDumpOptions O(outs());
O.Histogram = !NoHistogram;
@@ -123,8 +124,8 @@
O.DumpBlockinfo = DumpBlockinfo;
ExitOnErr(BA.analyze(
- Dump ? Optional<BCDumpOptions>(O) : Optional<BCDumpOptions>(None),
- CheckHash.empty() ? None : Optional<StringRef>(CheckHash)));
+ Dump ? std::optional<BCDumpOptions>(O) : std::optional<BCDumpOptions>(),
+ CheckHash.empty() ? std::nullopt : std::optional<StringRef>(CheckHash)));
if (Dump)
outs() << "\n\n";
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 b7b7730..7a54e26 100644
--- a/src/llvm-project/llvm/tools/llvm-c-test/echo.cpp
+++ b/src/llvm-project/llvm/tools/llvm-c-test/echo.cpp
@@ -159,6 +159,8 @@
return LLVMX86MMXTypeInContext(Ctx);
case LLVMTokenTypeKind:
return LLVMTokenTypeInContext(Ctx);
+ case LLVMTargetExtTypeKind:
+ assert(false && "Implement me");
}
fprintf(stderr, "%d is not a supported typekind\n", Kind);
@@ -1374,7 +1376,7 @@
}
}
-int llvm_echo(bool OpaquePointers) {
+int llvm_echo(void) {
LLVMEnablePrettyStackTrace();
LLVMModuleRef Src = llvm_load_module(false, true);
@@ -1383,8 +1385,6 @@
size_t ModuleIdentLen;
const char *ModuleName = LLVMGetModuleIdentifier(Src, &ModuleIdentLen);
LLVMContextRef Ctx = LLVMContextCreate();
- if (!OpaquePointers)
- LLVMContextSetOpaquePointers(Ctx, false);
LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleName, Ctx);
LLVMSetSourceFileName(M, SourceFileName, SourceFileLen);
diff --git a/src/llvm-project/llvm/tools/llvm-c-test/include-all.c b/src/llvm-project/llvm/tools/llvm-c-test/include-all.c
index 144393a..69ed753 100644
--- a/src/llvm-project/llvm/tools/llvm-c-test/include-all.c
+++ b/src/llvm-project/llvm/tools/llvm-c-test/include-all.c
@@ -35,7 +35,6 @@
#include "llvm-c/Support.h"
#include "llvm-c/Target.h"
#include "llvm-c/TargetMachine.h"
-#include "llvm-c/Transforms/AggressiveInstCombine.h"
#include "llvm-c/Transforms/InstCombine.h"
#include "llvm-c/Transforms/IPO.h"
#include "llvm-c/Transforms/PassManagerBuilder.h"
diff --git a/src/llvm-project/llvm/tools/llvm-c-test/llvm-c-test.h b/src/llvm-project/llvm/tools/llvm-c-test/llvm-c-test.h
index 7c08423..b828a82 100644
--- a/src/llvm-project/llvm/tools/llvm-c-test/llvm-c-test.h
+++ b/src/llvm-project/llvm/tools/llvm-c-test/llvm-c-test.h
@@ -50,7 +50,7 @@
int llvm_targets_list(void);
// echo.c
-int llvm_echo(bool OpaquePointers);
+int llvm_echo(void);
// diagnostic.c
int llvm_test_diagnostic_handler(void);
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 2d010b8..89a43db 100644
--- a/src/llvm-project/llvm/tools/llvm-c-test/main.c
+++ b/src/llvm-project/llvm/tools/llvm-c-test/main.c
@@ -95,9 +95,8 @@
return llvm_test_function_attributes();
} else if (argc == 2 && !strcmp(argv[1], "--test-callsite-attributes")) {
return llvm_test_callsite_attributes();
- } else if ((argc == 2 || argc == 3) && !strcmp(argv[1], "--echo")) {
- return llvm_echo(argc == 3 ? strcmp(argv[2], "--no-opaque-pointers") != 0
- : 1);
+ } else if (argc == 2 && !strcmp(argv[1], "--echo")) {
+ return llvm_echo();
} else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) {
return llvm_test_diagnostic_handler();
} else if (argc == 2 && !strcmp(argv[1], "--test-dibuilder")) {
diff --git a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/CMakeLists.txt
index 679bffe..03a7eae 100644
--- a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/CMakeLists.txt
@@ -5,6 +5,7 @@
Object
Support
Symbolize
+ TargetParser
)
add_llvm_library(LLVMCFIVerify
diff --git a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
index e8990c3..3e03c82 100644
--- a/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
@@ -96,7 +96,11 @@
}
Analysis.ObjectTriple = Analysis.Object->makeTriple();
- Analysis.Features = Analysis.Object->getFeatures();
+ Expected<SubtargetFeatures> Features = Analysis.Object->getFeatures();
+ if (!Features)
+ return Features.takeError();
+
+ Analysis.Features = *Features;
// Init the rest of the object.
if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
@@ -365,7 +369,7 @@
void FileAnalysis::printInstruction(const Instr &InstrMeta,
raw_ostream &OS) const {
- Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo.get(), OS);
+ Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo, OS);
}
Error FileAnalysis::initialiseDisassemblyMembers() {
diff --git a/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt
index 6faee03..35b8b21 100644
--- a/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-config/CMakeLists.txt
@@ -1,4 +1,7 @@
-set(LLVM_LINK_COMPONENTS support)
+set(LLVM_LINK_COMPONENTS
+ Support
+ TargetParser
+ )
set(BUILDVARIABLES_SRCPATH ${CMAKE_CURRENT_SOURCE_DIR}/BuildVariables.inc.in)
set(BUILDVARIABLES_OBJPATH ${CMAKE_CURRENT_BINARY_DIR}/BuildVariables.inc)
@@ -77,7 +80,7 @@
configure_file(${BUILDVARIABLES_SRCPATH} ${BUILDVARIABLES_OBJPATH} @ONLY)
# Set build-time environment(s).
-add_definitions(-DCMAKE_CFG_INTDIR="${CMAKE_CFG_INTDIR}")
+add_compile_definitions(CMAKE_CFG_INTDIR="${CMAKE_CFG_INTDIR}")
if(LLVM_ENABLE_MODULES)
target_compile_options(llvm-config PUBLIC
@@ -88,10 +91,18 @@
# Add the dependency on the generation step.
add_file_dependencies(${CMAKE_CURRENT_SOURCE_DIR}/llvm-config.cpp ${BUILDVARIABLES_OBJPATH})
-if(CMAKE_CROSSCOMPILING AND NOT LLVM_CONFIG_PATH)
- build_native_tool(llvm-config LLVM_CONFIG_PATH)
- set(LLVM_CONFIG_PATH "${LLVM_CONFIG_PATH}" CACHE STRING "")
+if(CMAKE_CROSSCOMPILING)
+ if (LLVM_NATIVE_TOOL_DIR AND NOT LLVM_CONFIG_PATH)
+ if (EXISTS "${LLVM_NATIVE_TOOL_DIR}/llvm-config${LLVM_HOST_EXECUTABLE_SUFFIX}")
+ set(LLVM_CONFIG_PATH "${LLVM_NATIVE_TOOL_DIR}/llvm-config${LLVM_HOST_EXECUTABLE_SUFFIX}")
+ endif()
+ endif()
- add_custom_target(NativeLLVMConfig DEPENDS ${LLVM_CONFIG_PATH})
- add_dependencies(llvm-config NativeLLVMConfig)
+ if (NOT LLVM_CONFIG_PATH)
+ build_native_tool(llvm-config LLVM_CONFIG_PATH)
+ set(LLVM_CONFIG_PATH "${LLVM_CONFIG_PATH}" CACHE STRING "")
+
+ add_custom_target(NativeLLVMConfig DEPENDS ${LLVM_CONFIG_PATH})
+ add_dependencies(llvm-config NativeLLVMConfig)
+ endif()
endif()
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 2c6c55f..b1d795a 100644
--- a/src/llvm-project/llvm/tools/llvm-config/llvm-config.cpp
+++ b/src/llvm-project/llvm/tools/llvm-config/llvm-config.cpp
@@ -170,10 +170,8 @@
// Build a map of component names to information.
StringMap<AvailableComponent *> ComponentMap;
- for (unsigned i = 0; i != array_lengthof(AvailableComponents); ++i) {
- AvailableComponent *AC = &AvailableComponents[i];
- ComponentMap[AC->Name] = AC;
- }
+ for (auto &AC : AvailableComponents)
+ ComponentMap[AC.Name] = &AC;
// Visit the components.
for (unsigned i = 0, e = Components.size(); i != e; ++i) {
@@ -236,7 +234,6 @@
--obj-root Print the object root used to build LLVM.\n\
--prefix Print the installation prefix.\n\
--shared-mode Print how the provided components can be collectively linked (`shared` or `static`).\n\
- --src-root Print the source root LLVM was built from.\n\
--system-libs System Libraries needed to link against LLVM components.\n\
--targets-built List of all targets currently built.\n\
--version Print LLVM version.\n\
@@ -546,15 +543,14 @@
/// built, print LLVM_DYLIB_COMPONENTS instead of everything
/// in the manifest.
std::vector<std::string> Components;
- for (unsigned j = 0; j != array_lengthof(AvailableComponents); ++j) {
+ for (const auto &AC : AvailableComponents) {
// Only include non-installed components when in a development tree.
- if (!AvailableComponents[j].IsInstalled && !IsInDevelopmentTree)
+ if (!AC.IsInstalled && !IsInDevelopmentTree)
continue;
- Components.push_back(AvailableComponents[j].Name);
- if (AvailableComponents[j].Library && !IsInDevelopmentTree) {
- std::string path(
- GetComponentLibraryPath(AvailableComponents[j].Library, false));
+ Components.push_back(AC.Name);
+ if (AC.Library && !IsInDevelopmentTree) {
+ std::string path(GetComponentLibraryPath(AC.Library, false));
if (DirSep == "\\") {
std::replace(path.begin(), path.end(), '/', '\\');
}
@@ -595,8 +591,6 @@
PrintSharedMode = true;
} else if (Arg == "--obj-root") {
OS << ActivePrefix << '\n';
- } else if (Arg == "--src-root") {
- OS << LLVM_SRC_ROOT << '\n';
} else if (Arg == "--ignore-libllvm") {
LinkDyLib = false;
LinkMode = BuiltSharedLibs ? LinkModeShared : LinkModeAuto;
@@ -660,7 +654,7 @@
}
WithColor::error(errs(), "llvm-config")
<< "component libraries and shared library\n\n";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LinkModeStatic:
for (auto &Lib : MissingLibs)
WithColor::error(errs(), "llvm-config") << "missing: " << Lib << "\n";
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-cov/CMakeLists.txt
index c3afec8..7acc87e 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-cov/CMakeLists.txt
@@ -1,4 +1,11 @@
-set(LLVM_LINK_COMPONENTS core support object coverage profiledata)
+set(LLVM_LINK_COMPONENTS
+ Core
+ Support
+ Object
+ Coverage
+ ProfileData
+ TargetParser
+ )
add_llvm_tool(llvm-cov
llvm-cov.cpp
@@ -14,3 +21,5 @@
SourceCoverageViewText.cpp
TestingSupport.cpp
)
+
+target_link_libraries(llvm-cov PRIVATE LLVMDebuginfod)
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp b/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp
index 13b6c30..7b71d5a 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -23,6 +23,10 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Debuginfod/BuildIDFetcher.h"
+#include "llvm/Debuginfod/Debuginfod.h"
+#include "llvm/Debuginfod/HTTPClient.h"
+#include "llvm/Object/BuildID.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/CommandLine.h"
@@ -41,6 +45,7 @@
#include <functional>
#include <map>
+#include <optional>
#include <system_error>
using namespace llvm;
@@ -84,7 +89,7 @@
bool isEquivalentFile(StringRef FilePath1, StringRef FilePath2);
/// Retrieve a file status with a cache.
- Optional<sys::fs::file_status> getFileStatus(StringRef FilePath);
+ std::optional<sys::fs::file_status> getFileStatus(StringRef FilePath);
/// Return a memory buffer for the given source file.
ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
@@ -157,10 +162,10 @@
/// The coverage data path to be remapped from, and the source path to be
/// remapped to, when using -path-equivalence.
- Optional<std::pair<std::string, std::string>> PathRemapping;
+ std::optional<std::pair<std::string, std::string>> PathRemapping;
/// File status cache used when finding the same file.
- StringMap<Optional<sys::fs::file_status>> FileStatusCache;
+ StringMap<std::optional<sys::fs::file_status>> FileStatusCache;
/// The architecture the coverage mapping data targets.
std::vector<StringRef> CoverageArches;
@@ -178,6 +183,8 @@
/// Allowlist from -name-allowlist to be used for filtering.
std::unique_ptr<SpecialCaseList> NameAllowlist;
+
+ std::unique_ptr<object::BuildIDFetcher> BIDFetcher;
};
}
@@ -248,7 +255,7 @@
}
}
-Optional<sys::fs::file_status>
+std::optional<sys::fs::file_status>
CodeCoverageTool::getFileStatus(StringRef FilePath) {
auto It = FileStatusCache.try_emplace(FilePath);
auto &CachedStatus = It.first->getValue();
@@ -434,7 +441,7 @@
ObjectFilename);
auto CoverageOrErr =
CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches,
- ViewOpts.CompilationDirectory);
+ ViewOpts.CompilationDirectory, BIDFetcher.get());
if (Error E = CoverageOrErr.takeError()) {
error("Failed to load coverage: " + toString(std::move(E)));
return nullptr;
@@ -553,13 +560,16 @@
// Invoke the demangler.
std::vector<StringRef> ArgsV;
+ ArgsV.reserve(ViewOpts.DemanglerOpts.size());
for (StringRef Arg : ViewOpts.DemanglerOpts)
ArgsV.push_back(Arg);
- Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
+ std::optional<StringRef> Redirects[] = {
+ InputPath.str(), OutputPath.str(), {""}};
std::string ErrMsg;
- int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV,
- /*env=*/None, Redirects, /*secondsToWait=*/0,
- /*memoryLimit=*/0, &ErrMsg);
+ int RC =
+ sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV,
+ /*env=*/std::nullopt, Redirects, /*secondsToWait=*/0,
+ /*memoryLimit=*/0, &ErrMsg);
if (RC) {
error(ErrMsg, ViewOpts.DemanglerOpts[0]);
return;
@@ -625,7 +635,7 @@
"dump-collected-objects", cl::Optional, cl::Hidden,
cl::desc("Show the collected coverage object files"));
- cl::list<std::string> InputSourceFiles(cl::Positional,
+ cl::list<std::string> InputSourceFiles("sources", cl::Positional,
cl::desc("<Source files>"));
cl::opt<bool> DebugDumpCollectedPaths(
@@ -643,6 +653,14 @@
cl::opt<bool> DebugDump("dump", cl::Optional,
cl::desc("Show internal debug dump"));
+ cl::list<std::string> DebugFileDirectory(
+ "debug-file-directory",
+ cl::desc("Directories to search for object files by build ID"));
+ cl::opt<bool> Debuginfod(
+ "debuginfod", cl::ZeroOrMore,
+ cl::desc("Use debuginfod to look up object files from profile"),
+ cl::init(canUseDebuginfod()));
+
cl::opt<CoverageViewOptions::OutputFormat> Format(
"format", cl::desc("Output format for line-based coverage reports"),
cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
@@ -671,13 +689,6 @@
"file"),
cl::cat(FilteringCategory));
- // Allow for accepting previous option name.
- cl::list<std::string> NameFilterFilesDeprecated(
- "name-whitelist", cl::Optional, cl::Hidden,
- cl::desc("Show code coverage only for functions listed in the given "
- "file. Deprecated, use -name-allowlist instead"),
- cl::cat(FilteringCategory));
-
cl::list<std::string> NameRegexFilters(
"name-regex", cl::Optional,
cl::desc("Show code coverage only for functions that match the given "
@@ -752,12 +763,18 @@
auto commandLineParser = [&, this](int argc, const char **argv) -> int {
cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
ViewOpts.Debug = DebugDump;
+ if (Debuginfod) {
+ HTTPClient::initialize();
+ BIDFetcher = std::make_unique<DebuginfodFetcher>(DebugFileDirectory);
+ } else {
+ BIDFetcher = std::make_unique<object::BuildIDFetcher>(DebugFileDirectory);
+ }
if (!CovFilename.empty())
ObjectFilenames.emplace_back(CovFilename);
for (const std::string &Filename : CovFilenames)
ObjectFilenames.emplace_back(Filename);
- if (ObjectFilenames.empty()) {
+ if (ObjectFilenames.empty() && !Debuginfod && DebugFileDirectory.empty()) {
errs() << "No filenames specified!\n";
::exit(1);
}
@@ -815,16 +832,10 @@
}
// Read in -name-allowlist files.
- if (!NameFilterFiles.empty() || !NameFilterFilesDeprecated.empty()) {
+ if (!NameFilterFiles.empty()) {
std::string SpecialCaseListErr;
- if (!NameFilterFiles.empty())
- NameAllowlist = SpecialCaseList::create(
- NameFilterFiles, *vfs::getRealFileSystem(), SpecialCaseListErr);
- if (!NameFilterFilesDeprecated.empty())
- NameAllowlist = SpecialCaseList::create(NameFilterFilesDeprecated,
- *vfs::getRealFileSystem(),
- SpecialCaseListErr);
-
+ NameAllowlist = SpecialCaseList::create(
+ NameFilterFiles, *vfs::getRealFileSystem(), SpecialCaseListErr);
if (!NameAllowlist)
error(SpecialCaseListErr);
}
@@ -834,14 +845,9 @@
auto NameFilterer = std::make_unique<CoverageFilters>();
for (const auto &Name : NameFilters)
NameFilterer->push_back(std::make_unique<NameCoverageFilter>(Name));
- if (NameAllowlist) {
- if (!NameFilterFiles.empty())
- NameFilterer->push_back(
- std::make_unique<NameAllowlistCoverageFilter>(*NameAllowlist));
- if (!NameFilterFilesDeprecated.empty())
- NameFilterer->push_back(
- std::make_unique<NameWhitelistCoverageFilter>(*NameAllowlist));
- }
+ if (NameAllowlist && !NameFilterFiles.empty())
+ NameFilterer->push_back(
+ std::make_unique<NameAllowlistCoverageFilter>(*NameAllowlist));
for (const auto &Regex : NameRegexFilters)
NameFilterer->push_back(
std::make_unique<NameRegexCoverageFilter>(Regex));
@@ -881,10 +887,8 @@
}
CoverageArches.emplace_back(Arch);
}
- if (CoverageArches.size() == 1)
- CoverageArches.insert(CoverageArches.end(), ObjectFilenames.size() - 1,
- CoverageArches[0]);
- if (CoverageArches.size() != ObjectFilenames.size()) {
+ if (CoverageArches.size() != 1 &&
+ CoverageArches.size() != ObjectFilenames.size()) {
error("Number of architectures doesn't match the number of objects");
return 1;
}
@@ -1090,7 +1094,7 @@
FilenameFunctionMap;
for (const auto &SourceFile : SourceFiles)
for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
- if (Filters.matches(*Coverage.get(), Function))
+ if (Filters.matches(*Coverage, Function))
FilenameFunctionMap[SourceFile].push_back(&Function);
// Only print filter matching functions for each file.
@@ -1179,7 +1183,7 @@
if (!Coverage)
return 1;
- CoverageReport Report(ViewOpts, *Coverage.get());
+ CoverageReport Report(ViewOpts, *Coverage);
if (!ShowFunctionSummaries) {
if (SourceFiles.empty())
Report.renderFileReports(llvm::outs(), IgnoreFilenameFilters);
@@ -1210,12 +1214,17 @@
cl::desc("Don't export per-function data"),
cl::cat(ExportCategory));
+ cl::opt<bool> SkipBranches("skip-branches", cl::Optional,
+ cl::desc("Don't export branch data (LCOV)"),
+ cl::cat(ExportCategory));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
ViewOpts.SkipExpansions = SkipExpansions;
ViewOpts.SkipFunctions = SkipFunctions;
+ ViewOpts.SkipBranches = SkipBranches;
if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
@@ -1240,16 +1249,16 @@
switch (ViewOpts.Format) {
case CoverageViewOptions::OutputFormat::Text:
- Exporter = std::make_unique<CoverageExporterJson>(*Coverage.get(),
- ViewOpts, outs());
+ Exporter =
+ std::make_unique<CoverageExporterJson>(*Coverage, ViewOpts, outs());
break;
case CoverageViewOptions::OutputFormat::HTML:
// Unreachable because we should have gracefully terminated with an error
// above.
llvm_unreachable("Export in HTML is not supported!");
case CoverageViewOptions::OutputFormat::Lcov:
- Exporter = std::make_unique<CoverageExporterLcov>(*Coverage.get(),
- ViewOpts, outs());
+ Exporter =
+ std::make_unique<CoverageExporterLcov>(*Coverage, ViewOpts, outs());
break;
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 2e161f5..9e43377 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -48,7 +48,6 @@
#include "CoverageExporterJson.h"
#include "CoverageReport.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/ThreadPool.h"
@@ -291,8 +290,8 @@
const json::Object *ObjB = B.getAsObject();
assert(ObjA != nullptr && "Value A was not an Object");
assert(ObjB != nullptr && "Value B was not an Object");
- const StringRef FilenameA = ObjA->getString("filename").value();
- const StringRef FilenameB = ObjB->getString("filename").value();
+ const StringRef FilenameA = *ObjA->getString("filename");
+ const StringRef FilenameB = *ObjB->getString("filename");
return FilenameA.compare(FilenameB) < 0;
});
auto Export = json::Object(
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
index 0096a3d..ae8f556 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
@@ -173,7 +173,7 @@
void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport, bool ExportSummaryOnly,
- bool SkipFunctions) {
+ bool SkipFunctions, bool SkipBranches) {
OS << "SF:" << Filename << '\n';
if (!ExportSummaryOnly && !SkipFunctions) {
@@ -185,9 +185,11 @@
// Calculate and render detailed coverage information for given file.
auto FileCoverage = Coverage.getCoverageForFile(Filename);
renderLineExecutionCounts(OS, FileCoverage);
- renderBranchExecutionCounts(OS, Coverage, FileCoverage);
+ if (!SkipBranches)
+ renderBranchExecutionCounts(OS, Coverage, FileCoverage);
}
- renderBranchSummary(OS, FileReport);
+ if (!SkipBranches)
+ renderBranchSummary(OS, FileReport);
renderLineSummary(OS, FileReport);
OS << "end_of_record\n";
@@ -196,10 +198,11 @@
void renderFiles(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
ArrayRef<std::string> SourceFiles,
ArrayRef<FileCoverageSummary> FileReports,
- bool ExportSummaryOnly, bool SkipFunctions) {
+ bool ExportSummaryOnly, bool SkipFunctions,
+ bool SkipBranches) {
for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I)
renderFile(OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly,
- SkipFunctions);
+ SkipFunctions, SkipBranches);
}
} // end anonymous namespace
@@ -218,5 +221,5 @@
auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
SourceFiles, Options);
renderFiles(OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly,
- Options.SkipFunctions);
+ Options.SkipFunctions, Options.SkipBranches);
}
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.cpp
index b799864..bc1ddb4 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.cpp
@@ -40,13 +40,6 @@
return Allowlist.inSection("llvmcov", "allowlist_fun", Function.Name);
}
-// TODO: remove this when -name-whitelist option is removed.
-bool NameWhitelistCoverageFilter::matches(
- const coverage::CoverageMapping &,
- const coverage::FunctionRecord &Function) const {
- return Whitelist.inSection("llvmcov", "whitelist_fun", Function.Name);
-}
-
bool RegionCoverageFilter::matches(
const coverage::CoverageMapping &CM,
const coverage::FunctionRecord &Function) const {
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.h b/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.h
index 3040fe7..5345b0c 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageFilters.h
@@ -79,18 +79,6 @@
const coverage::FunctionRecord &Function) const override;
};
-// TODO: Remove this class when -name-whitelist option is removed.
-class NameWhitelistCoverageFilter : public CoverageFilter {
- const SpecialCaseList &Whitelist;
-
-public:
- NameWhitelistCoverageFilter(const SpecialCaseList &Whitelist)
- : Whitelist(Whitelist) {}
-
- bool matches(const coverage::CoverageMapping &CM,
- const coverage::FunctionRecord &Function) const override;
-};
-
/// Matches numbers that pass a certain threshold.
template <typename T> class StatisticThresholdFilter {
public:
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp b/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp
index c91edc2..be042aa 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -437,6 +437,7 @@
prepareFileReports(Coverage, Totals, Files, Options, Filters);
std::vector<StringRef> Filenames;
+ Filenames.reserve(FileReports.size());
for (const FileCoverageSummary &FCS : FileReports)
Filenames.emplace_back(FCS.Name);
adjustColumnWidths(Filenames, {});
diff --git a/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h b/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h
index c6e9981..fedf2df 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/src/llvm-project/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -41,6 +41,7 @@
bool ExportSummaryOnly;
bool SkipExpansions;
bool SkipFunctions;
+ bool SkipBranches;
OutputFormat Format;
BranchOutputType ShowBranches;
std::string ShowOutputDirectory;
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 46782c9..50e3dcc 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -12,11 +12,11 @@
#include "CoverageReport.h"
#include "SourceCoverageViewHTML.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
+#include <optional>
using namespace llvm;
@@ -533,7 +533,7 @@
// 1 to set the highlight for snippet 2, segment 2 to set the highlight for
// snippet 3, and so on.
- Optional<StringRef> Color;
+ std::optional<StringRef> Color;
SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
auto Highlight = [&](const std::string &Snippet, unsigned LC, unsigned RC) {
if (getOptions().Debug)
@@ -559,7 +559,7 @@
else if (CurSeg->Col == ExpansionCol)
Color = "cyan";
else
- Color = None;
+ Color = std::nullopt;
if (Color)
Snippets[I + 1] = Highlight(Snippets[I + 1], CurSeg->Col,
diff --git a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 948414a..40d4359 100644
--- a/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -12,10 +12,10 @@
#include "SourceCoverageViewText.h"
#include "CoverageReport.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
+#include <optional>
using namespace llvm;
@@ -102,7 +102,7 @@
auto *WrappedSegment = LCS.getWrappedSegment();
CoverageSegmentArray Segments = LCS.getLineSegments();
- Optional<raw_ostream::Colors> Highlight;
+ std::optional<raw_ostream::Colors> Highlight;
SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
// The first segment overlaps from a previous line, so we treat it specially.
@@ -127,7 +127,7 @@
else if (Col == ExpansionCol)
Highlight = raw_ostream::CYAN;
else
- Highlight = None;
+ Highlight = std::nullopt;
}
// Show the rest of the line.
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 6462017..9040237 100644
--- a/src/llvm-project/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
@@ -44,11 +44,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -60,9 +63,9 @@
#undef OPTION
};
-class CvtResOptTable : public opt::OptTable {
+class CvtResOptTable : public opt::GenericOptTable {
public:
- CvtResOptTable() : OptTable(InfoTable, true) {}
+ CvtResOptTable() : opt::GenericOptTable(InfoTable, true) {}
};
}
@@ -118,7 +121,7 @@
CvtResOptTable T;
unsigned MAI, MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
if (InputArgs.hasArg(OPT_HELP)) {
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 02f4c84..f35f626 100644
--- a/src/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
@@ -234,8 +234,8 @@
// Complete object locators in the MS-ABI start with '??_R4'
else if (SymName.startswith("??_R4")) {
CompleteObjectLocator COL;
- COL.Data = makeArrayRef(
- reinterpret_cast<const little32_t *>(SymContents.data()), 3);
+ COL.Data =
+ ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);
StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols);
collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);
COLs[SymName] = COL;
@@ -243,8 +243,8 @@
// Class hierarchy descriptors in the MS-ABI start with '??_R3'
else if (SymName.startswith("??_R3")) {
ClassHierarchyDescriptor CHD;
- CHD.Data = makeArrayRef(
- reinterpret_cast<const little32_t *>(SymContents.data()), 3);
+ CHD.Data =
+ ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);
StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols);
collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);
CHDs[SymName] = CHD;
@@ -259,7 +259,7 @@
// Base class descriptors in the MS-ABI start with '??_R1'
else if (SymName.startswith("??_R1")) {
BaseClassDescriptor BCD;
- BCD.Data = makeArrayRef(
+ BCD.Data = ArrayRef(
reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5);
StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols);
collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);
@@ -499,7 +499,7 @@
static void dumpArchive(const Archive *Arc) {
Error Err = Error::success();
- for (auto &ArcC : Arc->children(Err)) {
+ for (const auto &ArcC : Arc->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = ArcC.getAsBinary();
if (!ChildOrErr) {
// Ignore non-object files.
diff --git a/src/llvm-project/llvm/tools/llvm-cxxfilt/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-cxxfilt/CMakeLists.txt
index 367744b..cbc4c2d 100644
--- a/src/llvm-project/llvm/tools/llvm-cxxfilt/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-cxxfilt/CMakeLists.txt
@@ -2,6 +2,7 @@
Demangle
Option
Support
+ TargetParser
)
set(LLVM_TARGET_DEFINITIONS Opts.td)
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 1cea9e2..06f0a25 100644
--- a/src/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/src/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -32,11 +32,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define PREFIX(NAME, VALUE) \
+ static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
#include "Opts.inc"
#undef PREFIX
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -48,9 +51,11 @@
#undef OPTION
};
-class CxxfiltOptTable : public opt::OptTable {
+class CxxfiltOptTable : public opt::GenericOptTable {
public:
- CxxfiltOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+ CxxfiltOptTable() : opt::GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
};
} // namespace
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt
new file mode 100644
index 0000000..b36f5d7
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+ AllTargetsDescs
+ AllTargetsInfos
+ AllTargetsDisassemblers
+ BinaryFormat
+ DebugInfoLogicalView
+ DebugInfoCodeView
+ DebugInfoDWARF
+ DebugInfoPDB
+ MC
+ MCDisassembler
+ Object
+ Support
+ )
+
+add_llvm_tool(llvm-debuginfo-analyzer
+ llvm-debuginfo-analyzer.cpp
+ Options.cpp
+ )
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/Options.cpp b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
new file mode 100644
index 0000000..e5566b3
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
@@ -0,0 +1,501 @@
+//===-- options.cpp - Command line options for llvm-debuginfo-analyzer----===//
+//
+// 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 handles the command line options for llvm-debuginfo-analyzer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Options.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+using namespace llvm::logicalview::cmdline;
+
+/// @}
+/// Command line options.
+/// @{
+
+OffsetParser::OffsetParser(cl::Option &O) : parser<unsigned long long>(O) {}
+OffsetParser::~OffsetParser() = default;
+
+bool OffsetParser::parse(cl::Option &O, StringRef ArgName, StringRef Arg,
+ unsigned long long &Val) {
+ char *End;
+ std::string Argument(Arg);
+ Val = strtoull(Argument.c_str(), &End, 0);
+ if (*End)
+ // Print an error message if unrecognized character.
+ return O.error("'" + Arg + "' unrecognized character.");
+ return false;
+}
+
+LVOptions cmdline::ReaderOptions;
+
+//===----------------------------------------------------------------------===//
+// Specific options
+//===----------------------------------------------------------------------===//
+cl::list<std::string>
+ cmdline::InputFilenames(cl::desc("<input object files or .dSYM bundles>"),
+ cl::Positional, cl::ZeroOrMore);
+
+//===----------------------------------------------------------------------===//
+// '--attribute' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::AttributeCategory("Attribute Options",
+ "These control extra attributes that are "
+ "added when the element is printed.");
+
+// --attribute=<value>[,<value>,...]
+cl::list<LVAttributeKind> cmdline::AttributeOptions(
+ "attribute", cl::cat(AttributeCategory), cl::desc("Element attributes."),
+ cl::Hidden, cl::CommaSeparated,
+ values(clEnumValN(LVAttributeKind::All, "all", "Include all attributes."),
+ clEnumValN(LVAttributeKind::Argument, "argument",
+ "Template parameters replaced by its arguments."),
+ clEnumValN(LVAttributeKind::Base, "base",
+ "Base types (int, bool, etc.)."),
+ clEnumValN(LVAttributeKind::Coverage, "coverage",
+ "Symbol location coverage."),
+ clEnumValN(LVAttributeKind::Directories, "directories",
+ "Directories referenced in the debug information."),
+ clEnumValN(LVAttributeKind::Discarded, "discarded",
+ "Discarded elements by the linker."),
+ clEnumValN(LVAttributeKind::Discriminator, "discriminator",
+ "Discriminators for inlined function instances."),
+ clEnumValN(LVAttributeKind::Encoded, "encoded",
+ "Template arguments encoded in the template name."),
+ clEnumValN(LVAttributeKind::Extended, "extended",
+ "Advanced attributes alias."),
+ clEnumValN(LVAttributeKind::Filename, "filename",
+ "Filename where the element is defined."),
+ clEnumValN(LVAttributeKind::Files, "files",
+ "Files referenced in the debug information."),
+ clEnumValN(LVAttributeKind::Format, "format",
+ "Object file format name."),
+ clEnumValN(LVAttributeKind::Gaps, "gaps",
+ "Missing debug location (gaps)."),
+ clEnumValN(LVAttributeKind::Generated, "generated",
+ "Compiler generated elements."),
+ clEnumValN(LVAttributeKind::Global, "global",
+ "Element referenced across Compile Units."),
+ clEnumValN(LVAttributeKind::Inserted, "inserted",
+ "Generated inlined abstract references."),
+ clEnumValN(LVAttributeKind::Level, "level",
+ "Lexical scope level (File=0, Compile Unit=1)."),
+ clEnumValN(LVAttributeKind::Linkage, "linkage", "Linkage name."),
+ clEnumValN(LVAttributeKind::Local, "local",
+ "Element referenced only in the Compile Unit."),
+ clEnumValN(LVAttributeKind::Location, "location",
+ "Element debug location."),
+ clEnumValN(LVAttributeKind::Offset, "offset",
+ "Debug information offset."),
+ clEnumValN(LVAttributeKind::Pathname, "pathname",
+ "Pathname where the element is defined."),
+ clEnumValN(LVAttributeKind::Producer, "producer",
+ "Toolchain identification name."),
+ clEnumValN(LVAttributeKind::Publics, "publics",
+ "Function names that are public."),
+ clEnumValN(LVAttributeKind::Qualified, "qualified",
+ "The element type include parents in its name."),
+ clEnumValN(LVAttributeKind::Qualifier, "qualifier",
+ "Line qualifiers (Newstatement, BasicBlock, etc.)."),
+ clEnumValN(LVAttributeKind::Range, "range",
+ "Debug location ranges."),
+ clEnumValN(LVAttributeKind::Reference, "reference",
+ "Element declaration and definition references."),
+ clEnumValN(LVAttributeKind::Register, "register",
+ "Processor register names."),
+ clEnumValN(LVAttributeKind::Standard, "standard",
+ "Basic attributes alias."),
+ clEnumValN(LVAttributeKind::Subrange, "subrange",
+ "Subrange encoding information for arrays."),
+ clEnumValN(LVAttributeKind::System, "system",
+ "Display PDB's MS system elements."),
+ clEnumValN(LVAttributeKind::Typename, "typename",
+ "Include Parameters in templates."),
+ clEnumValN(LVAttributeKind::Underlying, "underlying",
+ "Underlying type for type definitions."),
+ clEnumValN(LVAttributeKind::Zero, "zero", "Zero line numbers.")));
+
+//===----------------------------------------------------------------------===//
+// '--compare' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::CompareCategory("Compare Options",
+ "These control the view comparison.");
+
+// --compare-context
+static cl::opt<bool, true>
+ CompareContext("compare-context", cl::cat(CompareCategory),
+ cl::desc("Add the view as compare context."), cl::Hidden,
+ cl::ZeroOrMore, cl::location(ReaderOptions.Compare.Context),
+ cl::init(false));
+
+// --compare=<value>[,<value>,...]
+cl::list<LVCompareKind> cmdline::CompareElements(
+ "compare", cl::cat(CompareCategory), cl::desc("Elements to compare."),
+ cl::Hidden, cl::CommaSeparated,
+ values(clEnumValN(LVCompareKind::All, "all", "Compare all elements."),
+ clEnumValN(LVCompareKind::Lines, "lines", "Lines."),
+ clEnumValN(LVCompareKind::Scopes, "scopes", "Scopes."),
+ clEnumValN(LVCompareKind::Symbols, "symbols", "Symbols."),
+ clEnumValN(LVCompareKind::Types, "types", "Types.")));
+
+//===----------------------------------------------------------------------===//
+// '--output' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::OutputCategory("Output Options",
+ "These control the output generated.");
+
+// --output-file=<filename>
+cl::opt<std::string>
+ cmdline::OutputFilename("output-file", cl::cat(OutputCategory),
+ cl::desc("Redirect output to the specified file."),
+ cl::Hidden, cl::value_desc("filename"),
+ cl::init("-"));
+
+// --output-folder=<path>
+static cl::opt<std::string, true>
+ OutputFolder("output-folder", cl::cat(OutputCategory),
+ cl::desc("Folder name for view splitting."),
+ cl::value_desc("pathname"), cl::Hidden, cl::ZeroOrMore,
+ cl::location(ReaderOptions.Output.Folder));
+
+// --output-level=<level>
+static cl::opt<unsigned, true>
+ OutputLevel("output-level", cl::cat(OutputCategory),
+ cl::desc("Only print to a depth of N elements."),
+ cl::value_desc("N"), cl::Hidden, cl::ZeroOrMore,
+ cl::location(ReaderOptions.Output.Level), cl::init(-1U));
+
+// --ouput=<value>[,<value>,...]
+cl::list<LVOutputKind> cmdline::OutputOptions(
+ "output", cl::cat(OutputCategory), cl::desc("Outputs for view."),
+ cl::Hidden, cl::CommaSeparated,
+ values(clEnumValN(LVOutputKind::All, "all", "All outputs."),
+ clEnumValN(LVOutputKind::Split, "split",
+ "Split the output by Compile Units."),
+ clEnumValN(LVOutputKind::Text, "text",
+ "Use a free form text output."),
+ clEnumValN(LVOutputKind::Json, "json",
+ "Use JSON as the output format.")));
+
+// --output-sort
+static cl::opt<LVSortMode, true> OutputSort(
+ "output-sort", cl::cat(OutputCategory),
+ cl::desc("Primary key when ordering logical view (default: line)."),
+ cl::Hidden, cl::ZeroOrMore,
+ values(clEnumValN(LVSortMode::Kind, "kind", "Sort by element kind."),
+ clEnumValN(LVSortMode::Line, "line", "Sort by element line number."),
+ clEnumValN(LVSortMode::Name, "name", "Sort by element name."),
+ clEnumValN(LVSortMode::Offset, "offset", "Sort by element offset.")),
+ cl::location(ReaderOptions.Output.SortMode), cl::init(LVSortMode::Line));
+
+//===----------------------------------------------------------------------===//
+// '--print' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::PrintCategory("Print Options",
+ "These control which elements are printed.");
+
+// --print=<value>[,<value>,...]
+cl::list<LVPrintKind> cmdline::PrintOptions(
+ "print", cl::cat(PrintCategory), cl::desc("Element to print."),
+ cl::CommaSeparated,
+ values(clEnumValN(LVPrintKind::All, "all", "All elements."),
+ clEnumValN(LVPrintKind::Elements, "elements",
+ "Instructions, lines, scopes, symbols and types."),
+ clEnumValN(LVPrintKind::Instructions, "instructions",
+ "Assembler instructions."),
+ clEnumValN(LVPrintKind::Lines, "lines",
+ "Lines referenced in the debug information."),
+ clEnumValN(LVPrintKind::Scopes, "scopes",
+ "A lexical block (Function, Class, etc.)."),
+ clEnumValN(LVPrintKind::Sizes, "sizes",
+ "Scope contributions to the debug information."),
+ clEnumValN(LVPrintKind::Summary, "summary",
+ "Summary of elements missing/added/matched/printed."),
+ clEnumValN(LVPrintKind::Symbols, "symbols",
+ "Symbols (Variable, Members, etc.)."),
+ clEnumValN(LVPrintKind::Types, "types",
+ "Types (Pointer, Reference, etc.)."),
+ clEnumValN(LVPrintKind::Warnings, "warnings",
+ "Warnings detected.")));
+
+//===----------------------------------------------------------------------===//
+// '--report' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::ReportCategory("Report Options",
+ "These control how the elements are printed.");
+
+// --report=<value>[,<value>,...]
+cl::list<LVReportKind> cmdline::ReportOptions(
+ "report", cl::cat(ReportCategory),
+ cl::desc("Reports layout used for print, compare and select."), cl::Hidden,
+ cl::CommaSeparated,
+ values(clEnumValN(LVReportKind::All, "all", "Generate all reports."),
+ clEnumValN(LVReportKind::Children, "children",
+ "Selected elements are displayed in a tree view "
+ "(Include children)"),
+ clEnumValN(LVReportKind::List, "list",
+ "Selected elements are displayed in a tabular format."),
+ clEnumValN(LVReportKind::Parents, "parents",
+ "Selected elements are displayed in a tree view. "
+ "(Include parents)"),
+ clEnumValN(LVReportKind::View, "view",
+ "Selected elements are displayed in a tree view "
+ "(Include parents and children.")));
+
+//===----------------------------------------------------------------------===//
+// '--select' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::SelectCategory("Select Options",
+ "These control which elements are selected.");
+
+// --select-nocase
+static cl::opt<bool, true>
+ SelectIgnoreCase("select-nocase", cl::cat(SelectCategory),
+ cl::desc("Ignore case distinctions when searching."),
+ cl::Hidden, cl::ZeroOrMore,
+ cl::location(ReaderOptions.Select.IgnoreCase),
+ cl::init(false));
+
+// --select-regex
+static cl::opt<bool, true> SelectUseRegex(
+ "select-regex", cl::cat(SelectCategory),
+ cl::desc("Treat any <pattern> strings as regular expressions when "
+ "selecting instead of just as an exact string match."),
+ cl::Hidden, cl::ZeroOrMore, cl::location(ReaderOptions.Select.UseRegex),
+ cl::init(false));
+
+// --select=<pattern>
+cl::list<std::string> cmdline::SelectPatterns(
+ "select", cl::cat(SelectCategory),
+ cl::desc("Search elements matching the given pattern."), cl::Hidden,
+ cl::value_desc("pattern"), cl::CommaSeparated);
+
+// --select-offsets=<value>[,<value>,...]
+OffsetOptionList cmdline::SelectOffsets("select-offsets",
+ cl::cat(SelectCategory),
+ cl::desc("Offset element to print."),
+ cl::Hidden, cl::value_desc("offset"),
+ cl::CommaSeparated, cl::ZeroOrMore);
+
+// --select-elements=<value>[,<value>,...]
+cl::list<LVElementKind> cmdline::SelectElements(
+ "select-elements", cl::cat(SelectCategory),
+ cl::desc("Conditions to use when printing elements."), cl::Hidden,
+ cl::CommaSeparated,
+ values(clEnumValN(LVElementKind::Discarded, "Discarded",
+ "Discarded elements by the linker."),
+ clEnumValN(LVElementKind::Global, "Global",
+ "Element referenced across Compile Units."),
+ clEnumValN(LVElementKind::Optimized, "Optimized",
+ "Generated inlined abstract references.")));
+
+// --select-lines=<value>[,<value>,...]
+cl::list<LVLineKind> cmdline::SelectLines(
+ "select-lines", cl::cat(SelectCategory),
+ cl::desc("Line kind to use when printing lines."), cl::Hidden,
+ cl::CommaSeparated,
+ values(
+ clEnumValN(LVLineKind::IsAlwaysStepInto, "AlwaysStepInto",
+ "Always Step Into."),
+ clEnumValN(LVLineKind::IsBasicBlock, "BasicBlock", "Basic block."),
+ clEnumValN(LVLineKind::IsDiscriminator, "Discriminator",
+ "Discriminator."),
+ clEnumValN(LVLineKind::IsEndSequence, "EndSequence", "End sequence."),
+ clEnumValN(LVLineKind::IsEpilogueBegin, "EpilogueBegin.",
+ "Epilogue begin."),
+ clEnumValN(LVLineKind::IsLineDebug, "LineDebug", "Debug line."),
+ clEnumValN(LVLineKind::IsLineAssembler, "LineAssembler",
+ "Assembler line."),
+ clEnumValN(LVLineKind::IsNeverStepInto, "NeverStepInto",
+ "Never Step Into."),
+ clEnumValN(LVLineKind::IsNewStatement, "NewStatement",
+ "New statement."),
+ clEnumValN(LVLineKind::IsPrologueEnd, "PrologueEnd", "Prologue end.")));
+
+// --select-scopes=<value>[,<value>,...]
+cl::list<LVScopeKind> cmdline::SelectScopes(
+ "select-scopes", cl::cat(SelectCategory),
+ cl::desc("Scope kind to use when printing scopes."), cl::Hidden,
+ cl::CommaSeparated,
+ values(
+ clEnumValN(LVScopeKind::IsAggregate, "Aggregate",
+ "Class, Structure or Union."),
+ clEnumValN(LVScopeKind::IsArray, "Array", "Array."),
+ clEnumValN(LVScopeKind::IsBlock, "Block", "Lexical block."),
+ clEnumValN(LVScopeKind::IsCallSite, "CallSite", "Call site block."),
+ clEnumValN(LVScopeKind::IsCatchBlock, "CatchBlock",
+ "Exception catch block."),
+ clEnumValN(LVScopeKind::IsClass, "Class", "Class."),
+ clEnumValN(LVScopeKind::IsCompileUnit, "CompileUnit", "Compile unit."),
+ clEnumValN(LVScopeKind::IsEntryPoint, "EntryPoint",
+ "Function entry point."),
+ clEnumValN(LVScopeKind::IsEnumeration, "Enumeration", "Enumeration."),
+ clEnumValN(LVScopeKind::IsFunction, "Function", "Function."),
+ clEnumValN(LVScopeKind::IsFunctionType, "FunctionType",
+ "Function type."),
+ clEnumValN(LVScopeKind::IsInlinedFunction, "InlinedFunction",
+ "Inlined function."),
+ clEnumValN(LVScopeKind::IsLabel, "Label", "Label."),
+ clEnumValN(LVScopeKind::IsLexicalBlock, "LexicalBlock",
+ "Lexical block."),
+ clEnumValN(LVScopeKind::IsNamespace, "Namespace", "Namespace."),
+ clEnumValN(LVScopeKind::IsRoot, "Root", "Root."),
+ clEnumValN(LVScopeKind::IsStructure, "Structure", "Structure."),
+ clEnumValN(LVScopeKind::IsSubprogram, "Subprogram", "Subprogram."),
+ clEnumValN(LVScopeKind::IsTemplate, "Template", "Template."),
+ clEnumValN(LVScopeKind::IsTemplateAlias, "TemplateAlias",
+ "Template alias."),
+ clEnumValN(LVScopeKind::IsTemplatePack, "TemplatePack",
+ "Template pack."),
+ clEnumValN(LVScopeKind::IsTryBlock, "TryBlock", "Exception try block."),
+ clEnumValN(LVScopeKind::IsUnion, "Union", "Union.")));
+
+// --select-symbols=<value>[,<value>,...]
+cl::list<LVSymbolKind> cmdline::SelectSymbols(
+ "select-symbols", cl::cat(SelectCategory),
+ cl::desc("Symbol kind to use when printing symbols."), cl::Hidden,
+ cl::CommaSeparated,
+ values(clEnumValN(LVSymbolKind::IsCallSiteParameter, "CallSiteParameter",
+ "Call site parameter."),
+ clEnumValN(LVSymbolKind::IsConstant, "Constant", "Constant."),
+ clEnumValN(LVSymbolKind::IsInheritance, "Inheritance",
+ "Inheritance."),
+ clEnumValN(LVSymbolKind::IsMember, "Member", "Member."),
+ clEnumValN(LVSymbolKind::IsParameter, "Parameter", "Parameter."),
+ clEnumValN(LVSymbolKind::IsUnspecified, "Unspecified",
+ "Unspecified parameter."),
+ clEnumValN(LVSymbolKind::IsVariable, "Variable", "Variable.")));
+
+// --select-types=<value>[,<value>,...]
+cl::list<LVTypeKind> cmdline::SelectTypes(
+ "select-types", cl::cat(SelectCategory),
+ cl::desc("Type kind to use when printing types."), cl::Hidden,
+ cl::CommaSeparated,
+ values(
+ clEnumValN(LVTypeKind::IsBase, "Base", "Base Type (int, bool, etc.)."),
+ clEnumValN(LVTypeKind::IsConst, "Const", "Constant specifier."),
+ clEnumValN(LVTypeKind::IsEnumerator, "Enumerator", "Enumerator."),
+ clEnumValN(LVTypeKind::IsImport, "Import", "Import."),
+ clEnumValN(LVTypeKind::IsImportDeclaration, "ImportDeclaration",
+ "Import declaration."),
+ clEnumValN(LVTypeKind::IsImportModule, "ImportModule",
+ "Import module."),
+ clEnumValN(LVTypeKind::IsPointer, "Pointer", "Pointer."),
+ clEnumValN(LVTypeKind::IsPointerMember, "PointerMember",
+ "Pointer to member."),
+ clEnumValN(LVTypeKind::IsReference, "Reference", "Reference type."),
+ clEnumValN(LVTypeKind::IsRestrict, "Restrict", "Restrict specifier."),
+ clEnumValN(LVTypeKind::IsRvalueReference, "RvalueReference",
+ "Rvalue reference."),
+ clEnumValN(LVTypeKind::IsSubrange, "Subrange", "Array subrange."),
+ clEnumValN(LVTypeKind::IsTemplateParam, "TemplateParam",
+ "Template Parameter."),
+ clEnumValN(LVTypeKind::IsTemplateTemplateParam, "TemplateTemplateParam",
+ "Template template parameter."),
+ clEnumValN(LVTypeKind::IsTemplateTypeParam, "TemplateTypeParam",
+ "Template type parameter."),
+ clEnumValN(LVTypeKind::IsTemplateValueParam, "TemplateValueParam",
+ "Template value parameter."),
+ clEnumValN(LVTypeKind::IsTypedef, "Typedef", "Type definition."),
+ clEnumValN(LVTypeKind::IsUnspecified, "Unspecified",
+ "Unspecified type."),
+ clEnumValN(LVTypeKind::IsVolatile, "Volatile", "Volatile specifier.")));
+
+//===----------------------------------------------------------------------===//
+// '--warning' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::WarningCategory("Warning Options",
+ "These control the generated warnings.");
+
+// --warning=<value>[,<value>,...]
+cl::list<LVWarningKind> cmdline::WarningOptions(
+ "warning", cl::cat(WarningCategory), cl::desc("Warnings to generate."),
+ cl::Hidden, cl::CommaSeparated,
+ values(
+ clEnumValN(LVWarningKind::All, "all", "All warnings."),
+ clEnumValN(LVWarningKind::Coverages, "coverages",
+ "Invalid symbol coverages values."),
+ clEnumValN(LVWarningKind::Lines, "lines", "Debug lines that are zero."),
+ clEnumValN(LVWarningKind::Locations, "locations",
+ "Invalid symbol locations."),
+ clEnumValN(LVWarningKind::Ranges, "ranges", "Invalid code ranges.")));
+
+//===----------------------------------------------------------------------===//
+// '--internal' options
+//===----------------------------------------------------------------------===//
+cl::OptionCategory
+ cmdline::InternalCategory("Internal Options",
+ "Internal traces and extra debugging code.");
+
+// --internal=<value>[,<value>,...]
+cl::list<LVInternalKind> cmdline::InternalOptions(
+ "internal", cl::cat(InternalCategory), cl::desc("Traces to enable."),
+ cl::Hidden, cl::CommaSeparated,
+ values(
+ clEnumValN(LVInternalKind::All, "all", "Enable all traces."),
+ clEnumValN(LVInternalKind::Cmdline, "cmdline", "Print command line."),
+ clEnumValN(LVInternalKind::ID, "id", "Print unique element ID"),
+ clEnumValN(LVInternalKind::Integrity, "integrity",
+ "Check elements integrity."),
+ clEnumValN(LVInternalKind::None, "none", "Ignore element line number."),
+ clEnumValN(LVInternalKind::Tag, "tag", "Debug information tags.")));
+
+/// @}
+
+// Copy local options into a globally accessible data structure.
+void llvm::logicalview::cmdline::propagateOptions() {
+ // Traverse list of options and update the given set (Using case and Regex).
+ auto UpdatePattern = [&](auto &List, auto &Set, bool IgnoreCase,
+ bool UseRegex) {
+ if (!List.empty())
+ for (std::string &Pattern : List)
+ Set.insert((IgnoreCase && !UseRegex) ? StringRef(Pattern).lower()
+ : Pattern);
+ };
+
+ // Handle --select.
+ UpdatePattern(SelectPatterns, ReaderOptions.Select.Generic,
+ ReaderOptions.Select.IgnoreCase, ReaderOptions.Select.UseRegex);
+
+ // Traverse list of options and update the given set.
+ auto UpdateSet = [&](auto &List, auto &Set) {
+ std::copy(List.begin(), List.end(), std::inserter(Set, Set.begin()));
+ };
+
+ // Handle options sets.
+ UpdateSet(AttributeOptions, ReaderOptions.Attribute.Kinds);
+ UpdateSet(PrintOptions, ReaderOptions.Print.Kinds);
+ UpdateSet(OutputOptions, ReaderOptions.Output.Kinds);
+ UpdateSet(ReportOptions, ReaderOptions.Report.Kinds);
+ UpdateSet(WarningOptions, ReaderOptions.Warning.Kinds);
+ UpdateSet(InternalOptions, ReaderOptions.Internal.Kinds);
+
+ UpdateSet(SelectElements, ReaderOptions.Select.Elements);
+ UpdateSet(SelectLines, ReaderOptions.Select.Lines);
+ UpdateSet(SelectScopes, ReaderOptions.Select.Scopes);
+ UpdateSet(SelectSymbols, ReaderOptions.Select.Symbols);
+ UpdateSet(SelectTypes, ReaderOptions.Select.Types);
+ UpdateSet(SelectOffsets, ReaderOptions.Select.Offsets);
+ UpdateSet(CompareElements, ReaderOptions.Compare.Elements);
+
+ // Resolve any options dependencies (ie. --print=all should set other
+ // print options, etc.).
+ ReaderOptions.resolveDependencies();
+}
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/Options.h b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/Options.h
new file mode 100644
index 0000000..7f30141
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/Options.h
@@ -0,0 +1,81 @@
+//===-- Options.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 defines command line options used by llvm-debuginfo-analyzer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/Support/CommandLine.h"
+
+namespace llvm {
+namespace logicalview {
+namespace cmdline {
+
+class OffsetParser final : public llvm::cl::parser<unsigned long long> {
+public:
+ OffsetParser(llvm::cl::Option &O);
+ ~OffsetParser() override;
+
+ // Parse an argument representing an offset. Return true on error.
+ // If the prefix is 0, the base is octal, if the prefix is 0x or 0X, the
+ // base is hexadecimal, otherwise the base is decimal.
+ bool parse(llvm::cl::Option &O, StringRef ArgName, StringRef ArgValue,
+ unsigned long long &Val);
+};
+
+typedef llvm::cl::list<unsigned long long, bool, OffsetParser> OffsetOptionList;
+
+extern llvm::cl::OptionCategory AttributeCategory;
+extern llvm::cl::OptionCategory CompareCategory;
+extern llvm::cl::OptionCategory OutputCategory;
+extern llvm::cl::OptionCategory PrintCategory;
+extern llvm::cl::OptionCategory ReportCategory;
+extern llvm::cl::OptionCategory SelectCategory;
+extern llvm::cl::OptionCategory WarningCategory;
+extern llvm::cl::OptionCategory InternalCategory;
+
+extern llvm::cl::list<std::string> InputFilenames;
+extern llvm::cl::opt<std::string> OutputFilename;
+
+extern llvm::cl::list<std::string> SelectPatterns;
+
+extern llvm::cl::list<LVElementKind> SelectElements;
+extern llvm::cl::list<LVLineKind> SelectLines;
+extern llvm::cl::list<LVScopeKind> SelectScopes;
+extern llvm::cl::list<LVSymbolKind> SelectSymbols;
+extern llvm::cl::list<LVTypeKind> SelectTypes;
+extern OffsetOptionList SelectOffsets;
+
+extern llvm::cl::list<LVAttributeKind> AttributeOptions;
+extern llvm::cl::list<LVOutputKind> OutputOptions;
+extern llvm::cl::list<LVPrintKind> PrintOptions;
+extern llvm::cl::list<LVWarningKind> WarningOptions;
+extern llvm::cl::list<LVInternalKind> InternalOptions;
+
+extern llvm::cl::list<LVCompareKind> CompareElements;
+extern llvm::cl::list<LVReportKind> ReportOptions;
+
+extern LVOptions ReaderOptions;
+
+// Perform any additional post parse command line actions. Propagate the
+// values captured by the command line parser, into the generic reader.
+void propagateOptions();
+
+} // namespace cmdline
+} // namespace logicalview
+} // namespace llvm
+
+#endif // OPTIONS_H
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp
new file mode 100644
index 0000000..fb82ec0
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp
@@ -0,0 +1,141 @@
+//===-- llvm-debuginfo-analyzer.cpp - LLVM Debug info analysis utility ---===//
+//
+// 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 program is a utility that displays the logical view for the debug
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Options.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
+#include "llvm/Support/COM.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+
+using namespace llvm;
+using namespace logicalview;
+using namespace cmdline;
+
+/// Create formatted StringError object.
+static StringRef ToolName = "llvm-debuginfo-analyzer";
+template <typename... Ts>
+static void error(std::error_code EC, char const *Fmt, const Ts &...Vals) {
+ if (!EC)
+ return;
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ WithColor::error(errs(), ToolName) << Stream.str() << "\n";
+ exit(1);
+}
+
+static void error(Error EC) {
+ if (!EC)
+ return;
+ handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
+ errs() << "\n";
+ WithColor::error(errs(), ToolName) << EI.message() << ".\n";
+ exit(1);
+ });
+}
+
+/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
+/// replace it with individual entries for each of the object files inside the
+/// bundle otherwise return the input path.
+static std::vector<std::string> expandBundle(const std::string &InputPath) {
+ std::vector<std::string> BundlePaths;
+ SmallString<256> BundlePath(InputPath);
+ // Normalize input path. This is necessary to accept `bundle.dSYM/`.
+ sys::path::remove_dots(BundlePath);
+ // Manually open up the bundle to avoid introducing additional dependencies.
+ if (sys::fs::is_directory(BundlePath) &&
+ sys::path::extension(BundlePath) == ".dSYM") {
+ std::error_code EC;
+ sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
+ for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ const std::string &Path = Dir->path();
+ sys::fs::file_status Status;
+ EC = sys::fs::status(Path, Status);
+ error(EC, "%s", Path.c_str());
+ switch (Status.type()) {
+ case sys::fs::file_type::regular_file:
+ case sys::fs::file_type::symlink_file:
+ case sys::fs::file_type::type_unknown:
+ BundlePaths.push_back(Path);
+ break;
+ default: /*ignore*/;
+ }
+ }
+ }
+ if (BundlePaths.empty())
+ BundlePaths.push_back(InputPath);
+ return BundlePaths;
+}
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+
+ // Initialize targets and assembly printers/parsers.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ InitializeAllDisassemblers();
+
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+ cl::extrahelp HelpResponse(
+ "\nPass @FILE as argument to read options from FILE.\n");
+
+ cl::HideUnrelatedOptions(
+ {&AttributeCategory, &CompareCategory, &InternalCategory, &OutputCategory,
+ &PrintCategory, &ReportCategory, &SelectCategory, &WarningCategory});
+ cl::ParseCommandLineOptions(argc, argv,
+ "Printing a logical representation of low-level "
+ "debug information.\n");
+ cl::PrintOptionValues();
+
+ std::error_code EC;
+ ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None);
+ error(EC, "Unable to open output file %s", OutputFilename.c_str());
+ // Don't remove output file if we exit with an error.
+ OutputFile.keep();
+
+ // Defaults to a.out if no filenames specified.
+ if (InputFilenames.empty())
+ InputFilenames.push_back("a.out");
+
+ // Expand any .dSYM bundles to the individual object files contained therein.
+ std::vector<std::string> Objects;
+ for (const std::string &Filename : InputFilenames) {
+ std::vector<std::string> Objs = expandBundle(Filename);
+ Objects.insert(Objects.end(), Objs.begin(), Objs.end());
+ }
+
+ propagateOptions();
+ ScopedPrinter W(OutputFile.os());
+ LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+ // Print the command line.
+ if (options().getInternalCmdline()) {
+ raw_ostream &Stream = W.getOStream();
+ Stream << "\nCommand line:\n";
+ for (int Index = 0; Index < argc; ++Index)
+ Stream << " " << argv[Index] << "\n";
+ Stream << "\n";
+ }
+
+ // Create readers and perform requested tasks on them.
+ if (Error Err = ReaderHandler.process())
+ error(std::move(Err));
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/llvm-project/llvm/tools/llvm-debuginfod-find/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-debuginfod-find/CMakeLists.txt
index a045560..b98c431 100644
--- a/src/llvm-project/llvm/tools/llvm-debuginfod-find/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-debuginfod-find/CMakeLists.txt
@@ -1,6 +1,6 @@
set(LLVM_LINK_COMPONENTS
+ Object
Support
- Symbolize
)
add_llvm_tool(llvm-debuginfod-find
llvm-debuginfod-find.cpp
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 373353c..40350a0 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
@@ -15,7 +15,7 @@
///
//===----------------------------------------------------------------------===//
-#include "llvm/DebugInfo/Symbolize/DIFetcher.h"
+#include "llvm/Debuginfod/BuildIDFetcher.h"
#include "llvm/Debuginfod/Debuginfod.h"
#include "llvm/Debuginfod/HTTPClient.h"
#include "llvm/Support/CommandLine.h"
@@ -67,7 +67,7 @@
ExitOnError ExitOnErr;
-static std::string fetchDebugInfo(ArrayRef<uint8_t> BuildID);
+static std::string fetchDebugInfo(object::BuildIDRef BuildID);
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
@@ -92,7 +92,7 @@
errs() << "Build ID " << InputBuildID << " is not a hex string.\n";
exit(1);
}
- BuildID ID(IDString.begin(), IDString.end());
+ object::BuildID ID(IDString.begin(), IDString.end());
std::string Path;
if (FetchSource != "")
@@ -116,12 +116,12 @@
outs() << Path << "\n";
}
-// Find a debug binary in local build ID directories and via debuginfod.
-std::string fetchDebugInfo(ArrayRef<uint8_t> BuildID) {
- if (!DebugFileDirectory.empty()) {
- symbolize::LocalDIFetcher Fetcher(DebugFileDirectory);
- if (Optional<std::string> LocalPath = Fetcher.fetchBuildID(BuildID))
- return *LocalPath;
- }
- return ExitOnErr(getCachedOrDownloadDebuginfo(BuildID));
+// Find a debug file in local build ID directories and via debuginfod.
+std::string fetchDebugInfo(object::BuildIDRef BuildID) {
+ if (std::optional<std::string> Path =
+ DebuginfodFetcher(DebugFileDirectory).fetch(BuildID))
+ return *Path;
+ errs() << "Build ID " << llvm::toHex(BuildID, /*Lowercase=*/true)
+ << " could not be found.";
+ exit(1);
}
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 4bdefcd..6573bf0 100644
--- a/src/llvm-project/llvm/tools/llvm-diff/lib/DifferenceEngine.cpp
+++ b/src/llvm-project/llvm/tools/llvm-diff/lib/DifferenceEngine.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
@@ -119,14 +120,99 @@
const Value *SavedLHS;
const Value *SavedRHS;
- /// The current mapping from old local values to new local values.
+ // The current mapping from old local values to new local values.
DenseMap<const Value *, const Value *> Values;
- /// The current mapping from old blocks to new blocks.
+ // The current mapping from old blocks to new blocks.
DenseMap<const BasicBlock *, const BasicBlock *> Blocks;
+ // The tentative mapping from old local values while comparing a pair of
+ // basic blocks. Once the pair has been processed, the tentative mapping is
+ // committed to the Values map.
DenseSet<std::pair<const Value *, const Value *>> TentativeValues;
+ // Equivalence Assumptions
+ //
+ // For basic blocks in loops, some values in phi nodes may depend on
+ // values from not yet processed basic blocks in the loop. When encountering
+ // such values, we optimistically asssume their equivalence and store this
+ // assumption in a BlockDiffCandidate for the pair of compared BBs.
+ //
+ // Once we have diffed all BBs, for every BlockDiffCandidate, we check all
+ // stored assumptions using the Values map that stores proven equivalences
+ // between the old and new values, and report a diff if an assumption cannot
+ // be proven to be true.
+ //
+ // Note that after having made an assumption, all further determined
+ // equivalences implicitly depend on that assumption. These will not be
+ // reverted or reported if the assumption proves to be false, because these
+ // are considered indirect diffs caused by earlier direct diffs.
+ //
+ // We aim to avoid false negatives in llvm-diff, that is, ensure that
+ // whenever no diff is reported, the functions are indeed equal. If
+ // assumptions were made, this is not entirely clear, because in principle we
+ // could end up with a circular proof where the proof of equivalence of two
+ // nodes is depending on the assumption of their equivalence.
+ //
+ // To see that assumptions do not add false negatives, note that if we do not
+ // report a diff, this means that there is an equivalence mapping between old
+ // and new values that is consistent with all assumptions made. The circular
+ // dependency that exists on an IR value level does not exist at run time,
+ // because the values selected by the phi nodes must always already have been
+ // computed. Hence, we can prove equivalence of the old and new functions by
+ // considering step-wise parallel execution, and incrementally proving
+ // equivalence of every new computed value. Another way to think about it is
+ // to imagine cloning the loop BBs for every iteration, turning the loops
+ // into (possibly infinite) DAGs, and proving equivalence by induction on the
+ // iteration, using the computed value mapping.
+
+ // The class BlockDiffCandidate stores pairs which either have already been
+ // proven to differ, or pairs whose equivalence depends on assumptions to be
+ // verified later.
+ struct BlockDiffCandidate {
+ const BasicBlock *LBB;
+ const BasicBlock *RBB;
+ // Maps old values to assumed-to-be-equivalent new values
+ SmallDenseMap<const Value *, const Value *> EquivalenceAssumptions;
+ // If set, we already know the blocks differ.
+ bool KnownToDiffer;
+ };
+
+ // List of block diff candidates in the order found by processing.
+ // We generate reports in this order.
+ // For every LBB, there may only be one corresponding RBB.
+ SmallVector<BlockDiffCandidate> BlockDiffCandidates;
+ // Maps LBB to the index of its BlockDiffCandidate, if existing.
+ DenseMap<const BasicBlock *, uint64_t> BlockDiffCandidateIndices;
+
+ // Note: Every LBB must always be queried together with the same RBB.
+ // The returned reference is not permanently valid and should not be stored.
+ BlockDiffCandidate &getOrCreateBlockDiffCandidate(const BasicBlock *LBB,
+ const BasicBlock *RBB) {
+ auto It = BlockDiffCandidateIndices.find(LBB);
+ // Check if LBB already has a diff candidate
+ if (It == BlockDiffCandidateIndices.end()) {
+ // Add new one
+ BlockDiffCandidateIndices[LBB] = BlockDiffCandidates.size();
+ BlockDiffCandidates.push_back(
+ {LBB, RBB, SmallDenseMap<const Value *, const Value *>(), false});
+ return BlockDiffCandidates.back();
+ }
+ // Use existing one
+ BlockDiffCandidate &Result = BlockDiffCandidates[It->second];
+ assert(Result.RBB == RBB && "Inconsistent basic block pairing!");
+ return Result;
+ }
+
+ // Optionally passed to equivalence checker functions, so these can add
+ // assumptions in BlockDiffCandidates. Its presence controls whether
+ // assumptions are generated.
+ struct AssumptionContext {
+ // The two basic blocks that need the two compared values to be equivalent.
+ const BasicBlock *LBB;
+ const BasicBlock *RBB;
+ };
+
unsigned getUnprocPredCount(const BasicBlock *Block) const {
unsigned Count = 0;
for (const_pred_iterator I = pred_begin(Block), E = pred_end(Block); I != E;
@@ -180,7 +266,7 @@
void unify(const Instruction *L, const Instruction *R) {
DifferenceEngine::Context C(Engine, L, R);
- bool Result = diff(L, R, true, true);
+ bool Result = diff(L, R, true, true, true);
assert(!Result && "structural differences second time around?");
(void) Result;
if (!L->use_empty())
@@ -194,6 +280,26 @@
}
}
+ void checkAndReportDiffCandidates() {
+ for (BlockDiffCandidate &BDC : BlockDiffCandidates) {
+
+ // Check assumptions
+ for (const auto &[L, R] : BDC.EquivalenceAssumptions) {
+ auto It = Values.find(L);
+ if (It == Values.end() || It->second != R) {
+ BDC.KnownToDiffer = true;
+ break;
+ }
+ }
+
+ // Run block diff if the BBs differ
+ if (BDC.KnownToDiffer) {
+ DifferenceEngine::Context C(Engine, BDC.LBB, BDC.RBB);
+ runBlockDiff(BDC.LBB->begin(), BDC.RBB->begin());
+ }
+ }
+ }
+
void diff(const BasicBlock *L, const BasicBlock *R) {
DifferenceEngine::Context C(Engine, L, R);
@@ -206,9 +312,14 @@
// If the instructions differ, start the more sophisticated diff
// algorithm at the start of the block.
- if (diff(LeftI, RightI, false, false)) {
+ if (diff(LeftI, RightI, false, false, true)) {
TentativeValues.clear();
- return runBlockDiff(L->begin(), R->begin());
+ // Register (L, R) as diffing pair. Note that we could directly emit a
+ // block diff here, but this way we ensure all diffs are emitted in one
+ // consistent order, independent of whether the diffs were detected
+ // immediately or via invalid assumptions.
+ getOrCreateBlockDiffCandidate(L, R).KnownToDiffer = true;
+ return;
}
// Otherwise, tentatively unify them.
@@ -232,7 +343,9 @@
bool diffCallSites(const CallBase &L, const CallBase &R, bool Complain) {
// FIXME: call attributes
- if (!equivalentAsOperands(L.getCalledOperand(), R.getCalledOperand())) {
+ AssumptionContext AC = {L.getParent(), R.getParent()};
+ if (!equivalentAsOperands(L.getCalledOperand(), R.getCalledOperand(),
+ &AC)) {
if (Complain) Engine.log("called functions differ");
return true;
}
@@ -241,7 +354,7 @@
return true;
}
for (unsigned I = 0, E = L.arg_size(); I != E; ++I)
- if (!equivalentAsOperands(L.getArgOperand(I), R.getArgOperand(I))) {
+ if (!equivalentAsOperands(L.getArgOperand(I), R.getArgOperand(I), &AC)) {
if (Complain)
Engine.logf("arguments %l and %r differ")
<< L.getArgOperand(I) << R.getArgOperand(I);
@@ -250,9 +363,15 @@
return false;
}
+ // If AllowAssumptions is enabled, whenever we encounter a pair of values
+ // that we cannot prove to be equivalent, we assume equivalence and store that
+ // assumption to be checked later in BlockDiffCandidates.
bool diff(const Instruction *L, const Instruction *R, bool Complain,
- bool TryUnify) {
+ bool TryUnify, bool AllowAssumptions) {
// FIXME: metadata (if Complain is set)
+ AssumptionContext ACValue = {L->getParent(), R->getParent()};
+ // nullptr AssumptionContext disables assumption generation.
+ const AssumptionContext *AC = AllowAssumptions ? &ACValue : nullptr;
// Different opcodes always imply different operations.
if (L->getOpcode() != R->getOpcode()) {
@@ -291,7 +410,7 @@
tryUnify(LI.getIncomingBlock(I), RI.getIncomingBlock(I));
if (!equivalentAsOperands(LI.getIncomingValue(I),
- RI.getIncomingValue(I))) {
+ RI.getIncomingValue(I), AC)) {
if (Complain)
Engine.log("PHI node incoming values differ");
return true;
@@ -343,7 +462,7 @@
}
if (LI->isConditional()) {
- if (!equivalentAsOperands(LI->getCondition(), RI->getCondition())) {
+ if (!equivalentAsOperands(LI->getCondition(), RI->getCondition(), AC)) {
if (Complain) Engine.log("branch conditions differ");
return true;
}
@@ -360,7 +479,7 @@
return true;
}
- if (!equivalentAsOperands(LI->getAddress(), RI->getAddress())) {
+ if (!equivalentAsOperands(LI->getAddress(), RI->getAddress(), AC)) {
if (Complain) Engine.log("indirectbr addresses differ");
return true;
}
@@ -375,7 +494,7 @@
} else if (isa<SwitchInst>(L)) {
const SwitchInst *LI = cast<SwitchInst>(L);
const SwitchInst *RI = cast<SwitchInst>(R);
- if (!equivalentAsOperands(LI->getCondition(), RI->getCondition())) {
+ if (!equivalentAsOperands(LI->getCondition(), RI->getCondition(), AC)) {
if (Complain) Engine.log("switch conditions differ");
return true;
}
@@ -421,7 +540,7 @@
for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) {
Value *LO = L->getOperand(I), *RO = R->getOperand(I);
- if (!equivalentAsOperands(LO, RO)) {
+ if (!equivalentAsOperands(LO, RO, AC)) {
if (Complain) Engine.logf("operands %l and %r differ") << LO << RO;
return true;
}
@@ -431,7 +550,8 @@
}
public:
- bool equivalentAsOperands(const Constant *L, const Constant *R) {
+ bool equivalentAsOperands(const Constant *L, const Constant *R,
+ const AssumptionContext *AC) {
// Use equality as a preliminary filter.
if (L == R)
return true;
@@ -446,8 +566,8 @@
// Compare constant expressions structurally.
if (isa<ConstantExpr>(L))
- return equivalentAsOperands(cast<ConstantExpr>(L),
- cast<ConstantExpr>(R));
+ return equivalentAsOperands(cast<ConstantExpr>(L), cast<ConstantExpr>(R),
+ AC);
// Constants of the "same type" don't always actually have the same
// type; I don't know why. Just white-list them.
@@ -467,7 +587,7 @@
if (CVL->getType()->getNumElements() != CVR->getType()->getNumElements())
return false;
for (unsigned i = 0; i < CVL->getType()->getNumElements(); i++) {
- if (!equivalentAsOperands(CVL->getOperand(i), CVR->getOperand(i)))
+ if (!equivalentAsOperands(CVL->getOperand(i), CVR->getOperand(i), AC))
return false;
}
return true;
@@ -484,7 +604,7 @@
for (unsigned I = 0; I < CAL->getType()->getNumElements(); ++I) {
if (!equivalentAsOperands(CAL->getAggregateElement(I),
- CAR->getAggregateElement(I)))
+ CAR->getAggregateElement(I), AC))
return false;
}
@@ -520,7 +640,7 @@
continue;
}
- if (!equivalentAsOperands(LAgg, RAgg)) {
+ if (!equivalentAsOperands(LAgg, RAgg, AC)) {
return false;
}
}
@@ -531,7 +651,8 @@
return false;
}
- bool equivalentAsOperands(const ConstantExpr *L, const ConstantExpr *R) {
+ bool equivalentAsOperands(const ConstantExpr *L, const ConstantExpr *R,
+ const AssumptionContext *AC) {
if (L == R)
return true;
@@ -570,14 +691,25 @@
continue;
}
- if (!equivalentAsOperands(LOp, ROp))
+ if (!equivalentAsOperands(LOp, ROp, AC))
return false;
}
return true;
}
- bool equivalentAsOperands(const Value *L, const Value *R) {
+ // There are cases where we cannot determine whether two values are
+ // equivalent, because it depends on not yet processed basic blocks -- see the
+ // documentation on assumptions.
+ //
+ // AC is the context in which we are currently performing a diff.
+ // When we encounter a pair of values for which we can neither prove
+ // equivalence nor the opposite, we do the following:
+ // * If AC is nullptr, we treat the pair as non-equivalent.
+ // * If AC is set, we add an assumption for the basic blocks given by AC,
+ // and treat the pair as equivalent. The assumption is checked later.
+ bool equivalentAsOperands(const Value *L, const Value *R,
+ const AssumptionContext *AC) {
// Fall out if the values have different kind.
// This possibly shouldn't take priority over oracles.
if (L->getValueID() != R->getValueID())
@@ -587,10 +719,38 @@
// InlineAsm, MDNode, MDString, PseudoSourceValue
if (isa<Constant>(L))
- return equivalentAsOperands(cast<Constant>(L), cast<Constant>(R));
+ return equivalentAsOperands(cast<Constant>(L), cast<Constant>(R), AC);
- if (isa<Instruction>(L))
- return Values[L] == R || TentativeValues.count(std::make_pair(L, R));
+ if (isa<Instruction>(L)) {
+ auto It = Values.find(L);
+ if (It != Values.end())
+ return It->second == R;
+
+ if (TentativeValues.count(std::make_pair(L, R)))
+ return true;
+
+ // L and R might be equivalent, this could depend on not yet processed
+ // basic blocks, so we cannot decide here.
+ if (AC) {
+ // Add an assumption, unless there is a conflict with an existing one
+ BlockDiffCandidate &BDC =
+ getOrCreateBlockDiffCandidate(AC->LBB, AC->RBB);
+ auto InsertionResult = BDC.EquivalenceAssumptions.insert({L, R});
+ if (!InsertionResult.second && InsertionResult.first->second != R) {
+ // We already have a conflicting equivalence assumption for L, so at
+ // least one must be wrong, and we know that there is a diff.
+ BDC.KnownToDiffer = true;
+ BDC.EquivalenceAssumptions.clear();
+ return false;
+ }
+ // Optimistically assume equivalence, and check later once all BBs
+ // have been processed.
+ return true;
+ }
+
+ // Assumptions disabled, so pessimistically assume non-equivalence.
+ return false;
+ }
if (isa<Argument>(L))
return Values[L] == R;
@@ -613,6 +773,8 @@
Queue(QueueSorter(*this_())) {}
void diff(const Function *L, const Function *R) {
+ assert(Values.empty() && "Multiple diffs per engine are not supported!");
+
if (L->arg_size() != R->arg_size())
Engine.log("different argument counts");
@@ -624,6 +786,7 @@
tryUnify(&*L->begin(), &*R->begin());
processQueue();
+ checkAndReportDiffCandidates();
}
};
@@ -636,7 +799,7 @@
bool FunctionDifferenceEngine::matchForBlockDiff(const Instruction *L,
const Instruction *R) {
- return !diff(L, R, false, false);
+ return !diff(L, R, false, false, false);
}
void FunctionDifferenceEngine::runBlockDiff(BasicBlock::const_iterator LStart,
@@ -764,7 +927,7 @@
const CallInst *LCall = cast<CallInst>(&*I);
const InvokeInst *RInvoke = cast<InvokeInst>(RTerm);
if (!equivalentAsOperands(LCall->getCalledOperand(),
- RInvoke->getCalledOperand()))
+ RInvoke->getCalledOperand(), nullptr))
return;
if (!LCall->use_empty())
Values[LCall] = RInvoke;
@@ -778,7 +941,7 @@
const CallInst *RCall = cast<CallInst>(I);
const InvokeInst *LInvoke = cast<InvokeInst>(LTerm);
if (!equivalentAsOperands(LInvoke->getCalledOperand(),
- RCall->getCalledOperand()))
+ RCall->getCalledOperand(), nullptr))
return;
if (!LInvoke->use_empty())
Values[LInvoke] = RCall;
@@ -867,7 +1030,8 @@
if (GVL->hasLocalLinkage() && GVL->hasUniqueInitializer() &&
GVR->hasLocalLinkage() && GVR->hasUniqueInitializer())
return FunctionDifferenceEngine(*this, GVL, GVR)
- .equivalentAsOperands(GVL->getInitializer(), GVR->getInitializer());
+ .equivalentAsOperands(GVL->getInitializer(), GVR->getInitializer(),
+ nullptr);
}
return L->getName() == R->getName();
diff --git a/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt
index 148e54b..e709cd7 100644
--- a/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-driver/CMakeLists.txt
@@ -5,15 +5,17 @@
foreach(tool ${LLVM_DRIVER_TOOLS})
string(REPLACE "-" "_" tool_entry ${tool})
- string(REPLACE "llvm-" "" tool ${tool})
- set(def_decl "${def_decl}LLVM_DRIVER_TOOL(\"${tool}\", ${tool_entry})\n")
+ get_property(tool_aliases GLOBAL PROPERTY LLVM_DRIVER_TOOL_ALIASES_${tool})
+ foreach(alias ${tool_aliases})
+ set_property(GLOBAL APPEND PROPERTY LLVM_DRIVER_TOOL_SYMLINKS ${alias})
+ string(REPLACE "llvm-" "" alias ${alias})
+ set(def_decl "${def_decl}LLVM_DRIVER_TOOL(\"${alias}\", ${tool_entry})\n")
+ endforeach()
endforeach()
-get_property(LLVM_EXTRA_DRIVER_ENTRIES GLOBAL PROPERTY LLVM_EXTRA_DRIVER_ENTRIES)
-
file(WRITE
"${CMAKE_CURRENT_BINARY_DIR}/LLVMDriverTools.def"
- "${def_decl}${LLVM_EXTRA_DRIVER_ENTRIES}#undef LLVM_DRIVER_TOOL\n")
+ "${def_decl}#undef LLVM_DRIVER_TOOL\n")
target_include_directories(llvm-driver PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_sources(llvm-driver PRIVATE llvm-driver.cpp)
@@ -28,9 +30,8 @@
endif(APPLE)
macro(generate_driver_tool_targets)
- get_property(LLVM_DRIVER_TOOLS GLOBAL PROPERTY LLVM_DRIVER_TOOLS)
get_property(LLVM_DRIVER_TOOL_SYMLINKS GLOBAL PROPERTY LLVM_DRIVER_TOOL_SYMLINKS)
- foreach(name IN LISTS LLVM_DRIVER_TOOLS LLVM_DRIVER_TOOL_SYMLINKS)
+ foreach(name ${LLVM_DRIVER_TOOL_SYMLINKS})
add_llvm_tool_symlink(${name} llvm-driver ALWAYS_GENERATE)
# Always generate install targets
llvm_install_symlink(LLVM ${name} llvm-driver ALWAYS_GENERATE)
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 3f54336..a373daf 100644
--- a/src/llvm-project/llvm/tools/llvm-driver/llvm-driver.cpp
+++ b/src/llvm-project/llvm/tools/llvm-driver/llvm-driver.cpp
@@ -49,9 +49,15 @@
StringRef Stem = sys::path::stem(ToolName);
auto Is = [=](StringRef Tool) {
- auto I = Stem.rfind_insensitive(Tool);
- return I != StringRef::npos && (I + Tool.size() == Stem.size() ||
- !llvm::isAlnum(Stem[I + Tool.size()]));
+ auto IsImpl = [=](StringRef Stem) {
+ auto I = Stem.rfind_insensitive(Tool);
+ return I != StringRef::npos && (I + Tool.size() == Stem.size() ||
+ !llvm::isAlnum(Stem[I + Tool.size()]));
+ };
+ for (StringRef S : {Stem, sys::path::filename(ToolName)})
+ if (IsImpl(S))
+ return true;
+ return false;
};
#define LLVM_DRIVER_TOOL(tool, entry) \
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfdump/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-dwarfdump/CMakeLists.txt
index 58d8114..7c68aaa 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfdump/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-dwarfdump/CMakeLists.txt
@@ -5,6 +5,7 @@
MC
Object
Support
+ TargetParser
)
add_llvm_tool(llvm-dwarfdump
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp b/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp
index ed92665..a967abf 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -500,7 +500,8 @@
return;
// Handle any kind of lexical scope.
- const bool HasAbstractOrigin = Die.find(dwarf::DW_AT_abstract_origin) != None;
+ const bool HasAbstractOrigin =
+ Die.find(dwarf::DW_AT_abstract_origin) != std::nullopt;
const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
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 cc7f353..27330a5 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -18,6 +18,8 @@
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
@@ -137,8 +139,7 @@
// Options for dumping specific sections.
static unsigned DumpType = DIDT_Null;
-static std::array<llvm::Optional<uint64_t>, (unsigned)DIDT_ID_Count>
- DumpOffsets;
+static std::array<std::optional<uint64_t>, (unsigned)DIDT_ID_Count> DumpOffsets;
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
static opt<OPTION> Dump##ENUM_NAME(CMDLINE_NAME, \
desc("Dump the " ELF_NAME " section"), \
@@ -248,6 +249,13 @@
cl::desc("Show the sizes of all debug sections, "
"expressed in bytes."),
cat(DwarfDumpCategory));
+static cl::opt<bool> ManuallyGenerateUnitIndex(
+ "manaully-generate-unit-index",
+ cl::desc("if the input is dwp file, parse .debug_info "
+ "section and use it to populate "
+ "DW_SECT_INFO contributions in cu-index. "
+ "For DWARF5 it also populated TU Index."),
+ cl::init(false), cl::Hidden, cl::cat(DwarfDumpCategory));
static cl::opt<bool>
ShowSources("show-sources",
cl::desc("Show the sources across all compilation units."),
@@ -341,9 +349,11 @@
const Twine &, raw_ostream &)>;
/// Print only DIEs that have a certain name.
-static bool filterByName(const StringSet<> &Names, DWARFDie Die,
- StringRef NameRef, raw_ostream &OS) {
+static bool filterByName(
+ const StringSet<> &Names, DWARFDie Die, StringRef NameRef, raw_ostream &OS,
+ std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
DIDumpOptions DumpOpts = getDumpOpts(Die.getDwarfUnit()->getContext());
+ DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;
std::string Name =
(IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str();
if (UseRegex) {
@@ -369,24 +379,25 @@
}
/// Print only DIEs that have a certain name.
-static void filterByName(const StringSet<> &Names,
- DWARFContext::unit_iterator_range CUs,
- raw_ostream &OS) {
+static void filterByName(
+ 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};
if (const char *Name = Die.getName(DINameKind::ShortName))
- if (filterByName(Names, Die, Name, OS))
+ if (filterByName(Names, Die, Name, OS, GetNameForDWARFReg))
continue;
if (const char *Name = Die.getName(DINameKind::LinkageName))
- filterByName(Names, Die, Name, OS);
+ filterByName(Names, Die, Name, OS, GetNameForDWARFReg);
}
}
static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,
StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
for (const auto &Entry : Accel.equal_range(Name)) {
- if (llvm::Optional<uint64_t> Off = Entry.getDIESectionOffset()) {
+ if (std::optional<uint64_t> Off = Entry.getDIESectionOffset()) {
if (DWARFDie Die = DICtx.getDIEForOffset(*Off))
Dies.push_back(Die);
}
@@ -395,8 +406,8 @@
static DWARFDie toDie(const DWARFDebugNames::Entry &Entry,
DWARFContext &DICtx) {
- llvm::Optional<uint64_t> CUOff = Entry.getCUOffset();
- llvm::Optional<uint64_t> Off = Entry.getDIEUnitOffset();
+ std::optional<uint64_t> CUOff = Entry.getCUOffset();
+ std::optional<uint64_t> Off = Entry.getDIEUnitOffset();
if (!CUOff || !Off)
return DWARFDie();
@@ -404,7 +415,7 @@
if (!CU)
return DWARFDie();
- if (llvm::Optional<uint64_t> DWOId = CU->getDWOId()) {
+ if (std::optional<uint64_t> DWOId = CU->getDWOId()) {
// This is a skeleton unit. Look up the DIE in the DWO unit.
CU = DICtx.getDWOCompileUnitForHash(*DWOId);
if (!CU)
@@ -423,8 +434,9 @@
}
/// Print only DIEs that have a certain name.
-static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx,
- raw_ostream &OS) {
+static void filterByAccelName(
+ ArrayRef<std::string> Names, DWARFContext &DICtx, raw_ostream &OS,
+ std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
SmallVector<DWARFDie, 4> Dies;
for (const auto &Name : Names) {
getDies(DICtx, DICtx.getAppleNames(), Name, Dies);
@@ -436,6 +448,7 @@
Dies.erase(std::unique(Dies.begin(), Dies.end()), Dies.end());
DIDumpOptions DumpOpts = getDumpOpts(DICtx);
+ DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;
for (DWARFDie Die : Dies)
Die.dump(OS, 0, DumpOpts);
}
@@ -477,7 +490,7 @@
StringRef CompDir,
std::vector<std::string> &Sources) {
bool Result = true;
- llvm::Optional<uint64_t> LastIndex = LT.getLastValidFileIndex();
+ std::optional<uint64_t> LastIndex = LT.getLastValidFileIndex();
for (uint64_t I = LT.hasFileAtIndex(0) ? 0 : 1,
E = LastIndex ? *LastIndex + 1 : 0;
I < E; ++I) {
@@ -552,10 +565,41 @@
return Result;
}
+static std::unique_ptr<MCRegisterInfo>
+createRegInfo(const object::ObjectFile &Obj) {
+ std::unique_ptr<MCRegisterInfo> MCRegInfo;
+ Triple TT;
+ TT.setArch(Triple::ArchType(Obj.getArch()));
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::UnknownOS);
+ std::string TargetLookupError;
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TT.str(), TargetLookupError);
+ if (!TargetLookupError.empty())
+ return nullptr;
+ MCRegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
+ return MCRegInfo;
+}
+
static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
const Twine &Filename, raw_ostream &OS) {
- logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
- Filename.str() + ": ");
+
+ auto MCRegInfo = createRegInfo(Obj);
+ if (!MCRegInfo)
+ logAllUnhandledErrors(createStringError(inconvertibleErrorCode(),
+ "Error in creating MCRegInfo"),
+ errs(), Filename.str() + ": ");
+
+ auto GetRegName = [&MCRegInfo](uint64_t DwarfRegNum, bool IsEH) -> StringRef {
+ if (!MCRegInfo)
+ return {};
+ if (std::optional<unsigned> LLVMRegNum =
+ MCRegInfo->getLLVMRegNum(DwarfRegNum, IsEH))
+ if (const char *RegName = MCRegInfo->getName(*LLVMRegNum))
+ return StringRef(RegName);
+ return {};
+ };
+
// The UUID dump already contains all the same information.
if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
@@ -570,19 +614,21 @@
for (auto name : Name)
Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);
- filterByName(Names, DICtx.normal_units(), OS);
- filterByName(Names, DICtx.dwo_units(), OS);
+ filterByName(Names, DICtx.normal_units(), OS, GetRegName);
+ filterByName(Names, DICtx.dwo_units(), OS, GetRegName);
return true;
}
// Handle the --find option and lower it to --debug-info=<offset>.
if (!Find.empty()) {
- filterByAccelName(Find, DICtx, OS);
+ filterByAccelName(Find, DICtx, OS, GetRegName);
return true;
}
// Dump the complete DWARF structure.
- DICtx.dump(OS, getDumpOpts(DICtx), DumpOffsets);
+ auto DumpOpts = getDumpOpts(DICtx);
+ DumpOpts.GetNameForDWARFReg = GetRegName;
+ DICtx.dump(OS, DumpOpts, DumpOffsets);
return true;
}
@@ -636,6 +682,7 @@
std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
*Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
RecoverableErrorHandler);
+ DICtx->setParseCUTUIndexManually(ManuallyGenerateUnitIndex);
if (!HandleObj(*Obj, *DICtx, Filename, OS))
Result = false;
}
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt
index d932ff1..4210250 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/CMakeLists.txt
@@ -3,15 +3,16 @@
add_public_tablegen_target(DwarfutilTableGen)
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
DebugInfoDWARF
DWARFLinker
+ DWARFLinkerParallel
MC
ObjCopy
Object
Option
Support
Target
+ TargetParser
AllTargetsCodeGens
AllTargetsDescs
AllTargetsInfos
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index 3e70f46..ef222f8c 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -14,6 +14,7 @@
#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>
@@ -40,7 +41,7 @@
public:
ObjFileAddressMap(DWARFContext &Context, const Options &Options,
object::ObjectFile &ObjFile)
- : Opts(Options) {
+ : Opts(Options), Context(Context) {
// Remember addresses of existing text sections.
for (const object::SectionRef &Sect : ObjFile.sections()) {
if (!Sect.isText())
@@ -75,7 +76,7 @@
DIE.getTag() == dwarf::DW_TAG_label) &&
"Wrong type of input die");
- if (Optional<uint64_t> LowPC =
+ if (std::optional<uint64_t> LowPC =
dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
Opts.Tombstone,
@@ -137,17 +138,36 @@
void clear() override { DWARFAddressRanges.clear(); }
- llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t, uint64_t) override {
- // should not be called.
- return object::createError("no relocations in linked binary");
+ llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t StartOffset,
+ uint64_t EndOffset) override {
+ // No relocations in linked binary. Return just address value.
+
+ const char *AddrPtr =
+ Context.getDWARFObj().getAddrSection().Data.data() + StartOffset;
+ support::endianness Endianess =
+ Context.getDWARFObj().isLittleEndian() ? support::little : support::big;
+
+ assert(EndOffset > StartOffset);
+ switch (EndOffset - StartOffset) {
+ case 1:
+ return *AddrPtr;
+ case 2:
+ return support::endian::read16(AddrPtr, Endianess);
+ case 4:
+ return support::endian::read32(AddrPtr, Endianess);
+ case 8:
+ return support::endian::read64(AddrPtr, Endianess);
+ }
+
+ llvm_unreachable("relocateIndexedAddr unhandled case!");
}
protected:
// returns true if specified address range is inside address ranges
// of executable sections.
bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
- Optional<uint64_t> HighPC) {
- Optional<AddressRange> Range =
+ std::optional<uint64_t> HighPC) {
+ std::optional<AddressRange> Range =
TextAddressRanges.getRangeThatContains(LowPC);
if (HighPC)
@@ -156,7 +176,7 @@
return Range.has_value();
}
- uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
+ uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
uint16_t Version) {
if (LowPC == 0)
return true;
@@ -167,7 +187,8 @@
return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
}
- uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
+ uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,
+ std::optional<uint64_t> HighPC,
uint16_t Version, uint8_t AddressByteSize) {
if (Version <= 4 && HighPC) {
if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
@@ -182,7 +203,7 @@
return false;
}
- bool isDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
+ bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
uint16_t Version, TombstoneKind Tombstone,
uint8_t AddressByteSize) {
switch (Tombstone) {
@@ -202,13 +223,15 @@
bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
uint8_t AddressByteSize) {
- return isDeadAddressRange(LowPC, None, Version, Tombstone, AddressByteSize);
+ return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,
+ AddressByteSize);
}
private:
RangesTy DWARFAddressRanges;
AddressRanges TextAddressRanges;
const Options &Opts;
+ DWARFContext &Context;
};
static bool knownByDWARFUtil(StringRef SecName) {
@@ -229,9 +252,63 @@
.Case(".debug_macinfo", true)
.Case(".debug_str", true)
.Case(".debug_str_offsets", true)
+ .Case(".debug_pubnames", true)
+ .Case(".debug_pubtypes", true)
+ .Case(".debug_names", true)
.Default(false);
}
+static std::optional<DwarfLinkerAccelTableKind>
+getAcceleratorTableKind(StringRef SecName) {
+ return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName)
+ .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub)
+ .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub)
+ .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames)
+ .Default(std::nullopt);
+}
+
+static std::string getMessageForReplacedAcceleratorTables(
+ SmallVector<StringRef> &AccelTableNamesToReplace,
+ DwarfUtilAccelKind TargetTable) {
+ std::string Message;
+
+ Message += "'";
+ for (StringRef Name : AccelTableNamesToReplace) {
+ if (Message.size() > 1)
+ Message += ", ";
+ Message += Name;
+ }
+
+ Message += "' will be replaced with requested ";
+
+ switch (TargetTable) {
+ case DwarfUtilAccelKind::DWARF:
+ Message += ".debug_names table";
+ break;
+
+ default:
+ assert(false);
+ }
+
+ return Message;
+}
+
+static std::string getMessageForDeletedAcceleratorTables(
+ SmallVector<StringRef> &AccelTableNamesToReplace) {
+ std::string Message;
+
+ Message += "'";
+ for (StringRef Name : AccelTableNamesToReplace) {
+ if (Message.size() > 1)
+ Message += ", ";
+ Message += Name;
+ }
+
+ Message += "' will be deleted as no accelerator tables are requested";
+
+ return Message;
+}
+
Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
raw_pwrite_stream &OutStream) {
@@ -263,11 +340,12 @@
.str()))
return createStringError(std::errc::invalid_argument, "");
+ std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
+
// Create DWARF linker.
DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
DebugInfoLinker.setEstimatedObjfilesAmount(1);
- DebugInfoLinker.setAccelTableKind(DwarfLinkerAccelTableKind::None);
DebugInfoLinker.setErrorHandler(ReportErr);
DebugInfoLinker.setWarningHandler(ReportWarn);
DebugInfoLinker.setNumThreads(Options.NumThreads);
@@ -279,18 +357,6 @@
std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
std::vector<std::string> EmptyWarnings;
- std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
-
- // Unknown debug sections would be removed. Display warning
- // for such sections.
- for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
- if (isDebugSection(Sec.Name) && !knownByDWARFUtil(Sec.Name))
- warning(
- formatv("'{0}' is not currently supported: section will be skipped",
- Sec.Name),
- Options.InputFileName);
- }
-
// Add object files to the DWARFLinker.
AddresssMapForLinking[0] =
std::make_unique<ObjFileAddressMap>(*Context, Options, File);
@@ -299,8 +365,77 @@
File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
EmptyWarnings);
+ uint16_t MaxDWARFVersion = 0;
+ std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
+ [&MaxDWARFVersion](const DWARFUnit &Unit) {
+ MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
+ };
+
for (size_t I = 0; I < ObjectsForLinking.size(); I++)
- DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]);
+ DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr,
+ OnCUDieLoaded);
+
+ // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
+ if (MaxDWARFVersion == 0)
+ MaxDWARFVersion = 3;
+
+ if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion))
+ return Err;
+
+ SmallVector<DwarfLinkerAccelTableKind> AccelTables;
+
+ switch (Options.AccelTableKind) {
+ case DwarfUtilAccelKind::None:
+ // Nothing to do.
+ break;
+ case DwarfUtilAccelKind::DWARF:
+ // use .debug_names for all DWARF versions.
+ AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames);
+ break;
+ }
+
+ // Add accelerator tables to DWARFLinker.
+ for (DwarfLinkerAccelTableKind Table : AccelTables)
+ DebugInfoLinker.addAccelTableKind(Table);
+
+ SmallVector<StringRef> AccelTableNamesToReplace;
+ SmallVector<StringRef> AccelTableNamesToDelete;
+
+ // Unknown debug sections or non-requested accelerator sections would be
+ // removed. Display warning for such sections.
+ for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
+ if (isDebugSection(Sec.Name)) {
+ std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind =
+ getAcceleratorTableKind(Sec.Name);
+
+ if (SrcAccelTableKind) {
+ assert(knownByDWARFUtil(Sec.Name));
+
+ if (Options.AccelTableKind == DwarfUtilAccelKind::None)
+ AccelTableNamesToDelete.push_back(Sec.Name);
+ else if (std::find(AccelTables.begin(), AccelTables.end(),
+ *SrcAccelTableKind) == AccelTables.end())
+ AccelTableNamesToReplace.push_back(Sec.Name);
+ } else if (!knownByDWARFUtil(Sec.Name)) {
+ assert(!SrcAccelTableKind);
+ warning(
+ formatv("'{0}' is not currently supported: section will be skipped",
+ Sec.Name),
+ Options.InputFileName);
+ }
+ }
+ }
+
+ // Display message for the replaced accelerator tables.
+ if (!AccelTableNamesToReplace.empty())
+ warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
+ Options.AccelTableKind),
+ Options.InputFileName);
+
+ // Display message for the removed accelerator tables.
+ if (!AccelTableNamesToDelete.empty())
+ warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
+ Options.InputFileName);
// Link debug info.
if (Error Err = DebugInfoLinker.link())
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h
index c993200..38fa2b9 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.h
@@ -24,6 +24,12 @@
Exec, /// match with address range of executable sections.
};
+/// The kind of accelerator table.
+enum class DwarfUtilAccelKind : uint8_t {
+ None,
+ DWARF // DWARFv5: .debug_names
+};
+
struct Options {
std::string InputFileName;
std::string OutputFileName;
@@ -34,6 +40,7 @@
bool Verbose = false;
int NumThreads = 0;
bool Verify = false;
+ DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None;
std::string getSeparateDebugFileName() const {
return OutputFileName + ".debug";
diff --git a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td
index 4ab1b51..d454118 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/Options.td
@@ -5,6 +5,14 @@
def no_ # NAME: Flag<["--"], "no-" # name>, HelpText<help2>;
}
+def build_accelerator: Separate<["--", "-"], "build-accelerator">,
+ MetaVarName<"[none,DWARF]">,
+ HelpText<"Build accelerator tables(default: none)\n"
+ " =none - Do not build accelerators\n"
+ " =DWARF - .debug_names are generated for all DWARF versions\n"
+ >;
+def: Joined<["--", "-"], "build-accelerator=">, Alias<build_accelerator>;
+
def help : Flag<["--"], "help">,
HelpText<"Prints this help output">;
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 a6466be..74b6104 100644
--- a/src/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -40,11 +40,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "Options.inc"
#undef PREFIX
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -56,9 +59,9 @@
#undef OPTION
};
-class DwarfutilOptTable : public opt::OptTable {
+class DwarfutilOptTable : public opt::GenericOptTable {
public:
- DwarfutilOptTable() : OptTable(InfoTable) {}
+ DwarfutilOptTable() : opt::GenericOptTable(InfoTable) {}
};
} // namespace
@@ -120,6 +123,19 @@
formatv("unknown tombstone value: '{0}'", S).str().c_str());
}
+ if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
+ StringRef S = BuildAccelerator->getValue();
+
+ if (S == "none")
+ Options.AccelTableKind = DwarfUtilAccelKind::None;
+ else if (S == "DWARF")
+ Options.AccelTableKind = DwarfUtilAccelKind::DWARF;
+ else
+ return createStringError(
+ std::errc::invalid_argument,
+ formatv("unknown build-accelerator value: '{0}'", S).str().c_str());
+ }
+
if (Options.Verbose) {
if (Options.NumThreads != 1 && Args.hasArg(OPT_threads))
warning("--num-threads set to 1 because verbose mode is specified");
@@ -420,8 +436,9 @@
}
static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) {
- if (Opts.DoGarbageCollection) {
- verbose("Do garbage collection for debug info ...", Opts.Verbose);
+ if (Opts.DoGarbageCollection ||
+ Opts.AccelTableKind != DwarfUtilAccelKind::None) {
+ verbose("Do debug info linking...", Opts.Verbose);
DebugInfoBits LinkedDebugInfo;
raw_svector_ostream OutStream(LinkedDebugInfo);
@@ -458,7 +475,7 @@
DwarfutilOptTable T;
unsigned MAI;
unsigned MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
if (Args.hasArg(OPT_help) || Args.size() == 0) {
@@ -481,7 +498,6 @@
InitializeAllTargetMCs();
InitializeAllTargetInfos();
InitializeAllAsmPrinters();
- InitializeAllAsmParsers();
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
MemoryBuffer::getFileOrSTDIN(Opts.InputFileName);
diff --git a/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt
index 15210c4..3babab0 100644
--- a/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-dwp/CMakeLists.txt
@@ -7,6 +7,7 @@
MC
Object
Support
+ TargetParser
)
add_llvm_tool(llvm-dwp
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 d2d162d..0a2c1c1 100644
--- a/src/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp
+++ b/src/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
+#include <optional>
using namespace llvm;
using namespace llvm::object;
@@ -71,7 +72,10 @@
if (!DWOCompDir.empty()) {
SmallString<16> DWOPath(std::move(DWOName));
sys::fs::make_absolute(DWOCompDir, DWOPath);
- DWOPaths.emplace_back(DWOPath.data(), DWOPath.size());
+ if (!sys::fs::exists(DWOPath) && sys::fs::exists(DWOName))
+ DWOPaths.push_back(std::move(DWOName));
+ else
+ DWOPaths.emplace_back(DWOPath.data(), DWOPath.size());
} else {
DWOPaths.push_back(std::move(DWOName));
}
@@ -108,7 +112,13 @@
for (const auto &ExecFilename : ExecFilenames) {
auto DWOs = getDWOFilenames(ExecFilename);
if (!DWOs) {
- logAllUnhandledErrors(DWOs.takeError(), WithColor::error());
+ logAllUnhandledErrors(
+ handleErrors(DWOs.takeError(),
+ [&](std::unique_ptr<ECError> EC) -> Error {
+ return createFileError(ExecFilename,
+ Error(std::move(EC)));
+ }),
+ WithColor::error());
return 1;
}
DWOFilenames.insert(DWOFilenames.end(),
@@ -124,7 +134,13 @@
auto ErrOrTriple = readTargetTriple(DWOFilenames.front());
if (!ErrOrTriple) {
- logAllUnhandledErrors(ErrOrTriple.takeError(), WithColor::error());
+ logAllUnhandledErrors(
+ handleErrors(ErrOrTriple.takeError(),
+ [&](std::unique_ptr<ECError> EC) -> Error {
+ return createFileError(DWOFilenames.front(),
+ Error(std::move(EC)));
+ }),
+ WithColor::error());
return 1;
}
@@ -172,7 +188,7 @@
// Create the output file.
std::error_code EC;
ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_None);
- Optional<buffer_ostream> BOS;
+ std::optional<buffer_ostream> BOS;
raw_pwrite_stream *OS;
if (EC)
return error(Twine(OutputFilename) + ": " + EC.message(), Context);
@@ -180,7 +196,7 @@
OS = &OutFile.os();
} else {
BOS.emplace(OutFile.os());
- OS = BOS.getPointer();
+ OS = &*BOS;
}
std::unique_ptr<MCStreamer> MS(TheTarget->createMCObjectStreamer(
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-exegesis/CMakeLists.txt
index f1e1784..4ff1db9 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/CMakeLists.txt
@@ -1,8 +1,13 @@
set(LLVM_LINK_COMPONENTS
+ AllTargetsAsmParsers
+ AllTargetsCodeGens
+ AllTargetsDescs
+ AllTargetsDisassemblers
+ AllTargetsInfos
MC
MCParser
Support
- native
+ TargetParser
)
add_llvm_tool(llvm-exegesis
@@ -13,19 +18,17 @@
intrinsics_gen
)
+# Has side effect of defining LLVM_EXEGESIS_TARGETS
add_subdirectory(lib)
-# Link the native exegesis target if compiled and on the right host.
-if ((LLVM_TARGETS_TO_BUILD MATCHES "${LLVM_NATIVE_ARCH}") AND (LLVM_EXEGESIS_TARGETS MATCHES "${LLVM_NATIVE_ARCH}"))
- set(LLVM_EXEGESIS_NATIVE_ARCH "${LLVM_NATIVE_ARCH}")
-endif()
-
-if (LLVM_EXEGESIS_NATIVE_ARCH)
- set(LLVM_EXEGESIS_NATIVE_TARGET "LLVMExegesis${LLVM_EXEGESIS_NATIVE_ARCH}")
- set_source_files_properties(llvm-exegesis.cpp PROPERTIES COMPILE_FLAGS "-DLLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET=Initialize${LLVM_EXEGESIS_NATIVE_ARCH}ExegesisTarget")
-endif()
+# Link all enabled exegesis targets
+set(libs)
+foreach(t ${LLVM_EXEGESIS_TARGETS})
+ string(STRIP ${t} t)
+ list(APPEND libs "LLVMExegesis${t}")
+endforeach()
target_link_libraries(llvm-exegesis PRIVATE
LLVMExegesis
- ${LLVM_EXEGESIS_NATIVE_TARGET}
+ ${libs}
)
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/CMakeLists.txt
index e416d80..554eabd 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/CMakeLists.txt
@@ -8,6 +8,7 @@
Exegesis
Core
Support
+ MC
)
add_llvm_library(LLVMExegesisAArch64
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 b12f872..d1ec125 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp
@@ -102,6 +102,7 @@
void Analysis::writeSnippet(raw_ostream &OS, ArrayRef<uint8_t> Bytes,
const char *Separator) const {
SmallVector<std::string, 3> Lines;
+ const auto &SI = State_.getSubtargetInfo();
// Parse the asm snippet and print it.
while (!Bytes.empty()) {
MCInst MI;
@@ -114,7 +115,7 @@
}
SmallString<128> InstPrinterStr; // FIXME: magic number.
raw_svector_ostream OSS(InstPrinterStr);
- InstPrinter_->printInst(&MI, 0, "", *SubtargetInfo_, OSS);
+ InstPrinter_->printInst(&MI, 0, "", SI, OSS);
Bytes = Bytes.drop_front(MISize);
Lines.emplace_back(InstPrinterStr.str().trim());
}
@@ -136,10 +137,10 @@
const MCInst &MCI = Point.keyInstruction();
unsigned SchedClassId;
std::tie(SchedClassId, std::ignore) = ResolvedSchedClass::resolveSchedClassId(
- *SubtargetInfo_, *InstrInfo_, MCI);
+ State_.getSubtargetInfo(), State_.getInstrInfo(), MCI);
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
const MCSchedClassDesc *const SCDesc =
- SubtargetInfo_->getSchedModel().getSchedClassDesc(SchedClassId);
+ State_.getSubtargetInfo().getSchedModel().getSchedClassDesc(SchedClassId);
writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
#else
OS << SchedClassId;
@@ -151,38 +152,30 @@
OS << "\n";
}
-Analysis::Analysis(const Target &Target,
- std::unique_ptr<MCSubtargetInfo> SubtargetInfo,
- std::unique_ptr<MCInstrInfo> InstrInfo,
+Analysis::Analysis(const LLVMState &State,
const InstructionBenchmarkClustering &Clustering,
double AnalysisInconsistencyEpsilon,
- bool AnalysisDisplayUnstableOpcodes,
- const std::string &ForceCpuName)
- : Clustering_(Clustering), SubtargetInfo_(std::move(SubtargetInfo)),
- InstrInfo_(std::move(InstrInfo)),
+ bool AnalysisDisplayUnstableOpcodes)
+ : Clustering_(Clustering), State_(State),
AnalysisInconsistencyEpsilonSquared_(AnalysisInconsistencyEpsilon *
AnalysisInconsistencyEpsilon),
AnalysisDisplayUnstableOpcodes_(AnalysisDisplayUnstableOpcodes) {
if (Clustering.getPoints().empty())
return;
- const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
- const std::string CpuName =
- ForceCpuName.empty() ? FirstPoint.CpuName : ForceCpuName;
- RegInfo_.reset(Target.createMCRegInfo(FirstPoint.LLVMTriple));
MCTargetOptions MCOptions;
- AsmInfo_.reset(
- Target.createMCAsmInfo(*RegInfo_, FirstPoint.LLVMTriple, MCOptions));
- SubtargetInfo_.reset(
- Target.createMCSubtargetInfo(FirstPoint.LLVMTriple, CpuName, ""));
- InstPrinter_.reset(Target.createMCInstPrinter(
- Triple(FirstPoint.LLVMTriple), 0 /*default variant*/, *AsmInfo_,
- *InstrInfo_, *RegInfo_));
+ const auto &TM = State.getTargetMachine();
+ const auto &Triple = TM.getTargetTriple();
+ AsmInfo_.reset(TM.getTarget().createMCAsmInfo(State_.getRegInfo(),
+ Triple.str(), MCOptions));
+ InstPrinter_.reset(TM.getTarget().createMCInstPrinter(
+ Triple, 0 /*default variant*/, *AsmInfo_, State_.getInstrInfo(),
+ State_.getRegInfo()));
- Context_ =
- std::make_unique<MCContext>(Triple(FirstPoint.LLVMTriple), AsmInfo_.get(),
- RegInfo_.get(), SubtargetInfo_.get());
- Disasm_.reset(Target.createMCDisassembler(*SubtargetInfo_, *Context_));
+ Context_ = std::make_unique<MCContext>(
+ Triple, AsmInfo_.get(), &State_.getRegInfo(), &State_.getSubtargetInfo());
+ Disasm_.reset(TM.getTarget().createMCDisassembler(State_.getSubtargetInfo(),
+ *Context_));
assert(Disasm_ && "cannot create MCDisassembler. missing call to "
"InitializeXXXTargetDisassembler ?");
}
@@ -232,14 +225,14 @@
unsigned SchedClassId;
bool WasVariant;
std::tie(SchedClassId, WasVariant) =
- ResolvedSchedClass::resolveSchedClassId(*SubtargetInfo_, *InstrInfo_,
- MCI);
+ ResolvedSchedClass::resolveSchedClassId(State_.getSubtargetInfo(),
+ State_.getInstrInfo(), MCI);
const auto IndexIt = SchedClassIdToIndex.find(SchedClassId);
if (IndexIt == SchedClassIdToIndex.end()) {
// Create a new entry.
SchedClassIdToIndex.emplace(SchedClassId, Entries.size());
- ResolvedSchedClassAndPoints Entry(
- ResolvedSchedClass(*SubtargetInfo_, SchedClassId, WasVariant));
+ ResolvedSchedClassAndPoints Entry(ResolvedSchedClass(
+ State_.getSubtargetInfo(), SchedClassId, WasVariant));
Entry.PointIds.push_back(PointId);
Entries.push_back(std::move(Entry));
} else {
@@ -284,11 +277,11 @@
OS << "\">";
switch (Point.Mode) {
case InstructionBenchmark::Latency:
- writeLatencySnippetHtml(OS, Point.Key.Instructions, *InstrInfo_);
+ writeLatencySnippetHtml(OS, Point.Key.Instructions, State_.getInstrInfo());
break;
case InstructionBenchmark::Uops:
case InstructionBenchmark::InverseThroughput:
- writeParallelSnippetHtml(OS, Point.Key.Instructions, *InstrInfo_);
+ writeParallelSnippetHtml(OS, Point.Key.Instructions, State_.getInstrInfo());
break;
default:
llvm_unreachable("invalid mode");
@@ -314,7 +307,8 @@
OS << "</tr>";
for (const SchedClassCluster &Cluster : Clusters) {
OS << "<tr class=\""
- << (Cluster.measurementsMatch(*SubtargetInfo_, RSC, Clustering_,
+ << (Cluster.measurementsMatch(State_.getSubtargetInfo(), RSC,
+ Clustering_,
AnalysisInconsistencyEpsilonSquared_)
? "good-cluster"
: "bad-cluster")
@@ -383,15 +377,15 @@
"idealized unit resource (port) pressure assuming ideal "
"distribution\">Idealized Resource Pressure</th></tr>";
if (RSC.SCDesc->isValid()) {
- const auto &SM = SubtargetInfo_->getSchedModel();
+ const auto &SI = State_.getSubtargetInfo();
+ const auto &SM = SI.getSchedModel();
OS << "<tr><td>✔</td>";
OS << "<td>" << (RSC.WasVariant ? "✔" : "✕") << "</td>";
OS << "<td>" << RSC.SCDesc->NumMicroOps << "</td>";
// Latencies.
OS << "<td><ul>";
for (int I = 0, E = RSC.SCDesc->NumWriteLatencyEntries; I < E; ++I) {
- const auto *const Entry =
- SubtargetInfo_->getWriteLatencyEntry(RSC.SCDesc, I);
+ const auto *const Entry = SI.getWriteLatencyEntry(RSC.SCDesc, I);
OS << "<li>" << Entry->Cycles;
if (RSC.SCDesc->NumWriteLatencyEntries > 1) {
// Dismabiguate if more than 1 latency.
@@ -403,8 +397,7 @@
// inverse throughput.
OS << "<td>";
writeMeasurementValue<kEscapeHtml>(
- OS,
- MCSchedModel::getReciprocalThroughput(*SubtargetInfo_, *RSC.SCDesc));
+ OS, MCSchedModel::getReciprocalThroughput(SI, *RSC.SCDesc));
OS << "</td>";
// WriteProcRes.
OS << "<td><ul>";
@@ -419,9 +412,8 @@
OS << "<td><ul>";
for (const auto &Pressure : RSC.IdealizedProcResPressure) {
OS << "<li><span class=\"mono\">";
- writeEscaped<kEscapeHtml>(OS, SubtargetInfo_->getSchedModel()
- .getProcResource(Pressure.first)
- ->Name);
+ writeEscaped<kEscapeHtml>(
+ OS, SI.getSchedModel().getProcResource(Pressure.first)->Name);
OS << "</span>: ";
writeMeasurementValue<kEscapeHtml>(OS, Pressure.second);
OS << "</li>";
@@ -550,6 +542,7 @@
writeEscaped<kEscapeHtml>(OS, FirstPoint.CpuName);
OS << "</span></h3>";
+ const auto &SI = State_.getSubtargetInfo();
for (const auto &RSCAndPoints : makePointsPerSchedClass()) {
if (!RSCAndPoints.RSC.SCDesc)
continue;
@@ -574,10 +567,9 @@
// Print any scheduling class that has at least one cluster that does not
// match the checked-in data.
- if (all_of(SchedClassClusters, [this,
- &RSCAndPoints](const SchedClassCluster &C) {
- return C.measurementsMatch(*SubtargetInfo_, RSCAndPoints.RSC,
- Clustering_,
+ if (all_of(SchedClassClusters, [this, &RSCAndPoints,
+ &SI](const SchedClassCluster &C) {
+ return C.measurementsMatch(SI, RSCAndPoints.RSC, Clustering_,
AnalysisInconsistencyEpsilonSquared_);
}))
continue; // Nothing weird.
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 b6746be..a903fd2 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.h
@@ -36,12 +36,10 @@
// A helper class to analyze benchmark results for a target.
class Analysis {
public:
- Analysis(const Target &Target, std::unique_ptr<MCSubtargetInfo> SubtargetInfo,
- std::unique_ptr<MCInstrInfo> InstrInfo,
+ Analysis(const LLVMState &State,
const InstructionBenchmarkClustering &Clustering,
double AnalysisInconsistencyEpsilon,
- bool AnalysisDisplayUnstableOpcodes,
- const std::string &ForceCpuName = "");
+ bool AnalysisDisplayUnstableOpcodes);
// Prints a csv of instructions for each cluster.
struct PrintClusters {};
@@ -113,10 +111,8 @@
const char *Separator) const;
const InstructionBenchmarkClustering &Clustering_;
+ const LLVMState &State_;
std::unique_ptr<MCContext> Context_;
- std::unique_ptr<MCSubtargetInfo> SubtargetInfo_;
- std::unique_ptr<MCInstrInfo> InstrInfo_;
- std::unique_ptr<MCRegisterInfo> RegInfo_;
std::unique_ptr<MCAsmInfo> AsmInfo_;
std::unique_ptr<MCInstPrinter> InstPrinter_;
std::unique_ptr<MCDisassembler> Disasm_;
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 84fd929..0f8b765 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Assembler.cpp
@@ -209,6 +209,7 @@
// If the snippet setup is not complete, we disable liveliness tracking. This
// means that we won't know what values are in the registers.
+ // FIXME: this should probably be an assertion.
if (!IsSnippetSetupComplete)
Properties.reset(MachineFunctionProperties::Property::TracksLiveness);
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 dbf0769..673221e 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -23,7 +23,6 @@
static constexpr const char kIntegerPrefix[] = "i_0x";
static constexpr const char kDoublePrefix[] = "f_";
static constexpr const char kInvalidOperand[] = "INVALID";
-static constexpr llvm::StringLiteral kNoRegister("%noreg");
namespace llvm {
@@ -34,29 +33,8 @@
struct YamlContext {
YamlContext(const exegesis::LLVMState &State)
: State(&State), ErrorStream(LastError),
- OpcodeNameToOpcodeIdx(
- generateOpcodeNameToOpcodeIdxMapping(State.getInstrInfo())),
- RegNameToRegNo(generateRegNameToRegNoMapping(State.getRegInfo())) {}
-
- static StringMap<unsigned>
- generateOpcodeNameToOpcodeIdxMapping(const MCInstrInfo &InstrInfo) {
- StringMap<unsigned> Map(InstrInfo.getNumOpcodes());
- for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I)
- Map[InstrInfo.getName(I)] = I;
- assert(Map.size() == InstrInfo.getNumOpcodes() && "Size prediction failed");
- return Map;
- };
-
- StringMap<unsigned>
- generateRegNameToRegNoMapping(const MCRegisterInfo &RegInfo) {
- StringMap<unsigned> Map(RegInfo.getNumRegs());
- // Special-case RegNo 0, which would otherwise be spelled as ''.
- Map[kNoRegister] = 0;
- for (unsigned I = 1, E = RegInfo.getNumRegs(); I < E; ++I)
- Map[RegInfo.getName(I)] = I;
- assert(Map.size() == RegInfo.getNumRegs() && "Size prediction failed");
- return Map;
- };
+ OpcodeNameToOpcodeIdx(State.getOpcodeNameToOpcodeIdxMapping()),
+ RegNameToRegNo(State.getRegNameToRegNoMapping()) {}
void serializeMCInst(const MCInst &MCInst, raw_ostream &OS) {
OS << getInstrName(MCInst.getOpcode());
@@ -97,12 +75,12 @@
return RegName;
}
- Optional<unsigned> getRegNo(StringRef RegName) {
+ std::optional<unsigned> getRegNo(StringRef RegName) {
auto Iter = RegNameToRegNo.find(RegName);
if (Iter != RegNameToRegNo.end())
return Iter->second;
ErrorStream << "No register with name '" << RegName << "'\n";
- return None;
+ return std::nullopt;
}
private:
@@ -174,8 +152,8 @@
const exegesis::LLVMState *State;
std::string LastError;
raw_string_ostream ErrorStream;
- const StringMap<unsigned> OpcodeNameToOpcodeIdx;
- const StringMap<unsigned> RegNameToRegNo;
+ const DenseMap<StringRef, unsigned> &OpcodeNameToOpcodeIdx;
+ const DenseMap<StringRef, unsigned> &RegNameToRegNo;
};
} // namespace
@@ -264,7 +242,7 @@
String.split(Pieces, "=0x", /* MaxSplit */ -1,
/* KeepEmpty */ false);
YamlContext &Context = getTypedContext(Ctx);
- Optional<unsigned> RegNo;
+ std::optional<unsigned> RegNo;
if (Pieces.size() == 2 && (RegNo = Context.getRegNo(Pieces[0]))) {
RV.Register = *RegNo;
const unsigned BitsNeeded = APInt::getBitsNeeded(Pieces[1], kRadix);
@@ -327,47 +305,69 @@
}
};
+template <> struct MappingTraits<exegesis::InstructionBenchmark::TripleAndCpu> {
+ static void mapping(IO &Io,
+ exegesis::InstructionBenchmark::TripleAndCpu &Obj) {
+ assert(!Io.outputting() && "can only read TripleAndCpu");
+ // Read triple.
+ Io.mapRequired("llvm_triple", Obj.LLVMTriple);
+ Io.mapRequired("cpu_name", Obj.CpuName);
+ // Drop everything else.
+ }
+};
+
} // namespace yaml
namespace exegesis {
-Expected<InstructionBenchmark>
-InstructionBenchmark::readYaml(const LLVMState &State, StringRef Filename) {
- if (auto ExpectedMemoryBuffer =
- errorOrToExpected(MemoryBuffer::getFile(Filename, /*IsText=*/true))) {
- yaml::Input Yin(*ExpectedMemoryBuffer.get());
- YamlContext Context(State);
- InstructionBenchmark Benchmark;
- if (Yin.setCurrentDocument())
- yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
- if (!Context.getLastError().empty())
- return make_error<Failure>(Context.getLastError());
- return Benchmark;
- } else {
- return ExpectedMemoryBuffer.takeError();
+Expected<std::set<InstructionBenchmark::TripleAndCpu>>
+InstructionBenchmark::readTriplesAndCpusFromYamls(MemoryBufferRef Buffer) {
+ // We're only mapping a field, drop other fields and silence the corresponding
+ // warnings.
+ yaml::Input Yin(
+ Buffer, nullptr, +[](const SMDiagnostic &, void *Context) {});
+ Yin.setAllowUnknownKeys(true);
+ std::set<TripleAndCpu> Result;
+ yaml::EmptyContext Context;
+ while (Yin.setCurrentDocument()) {
+ TripleAndCpu TC;
+ yamlize(Yin, TC, /*unused*/ true, Context);
+ if (Yin.error())
+ return errorCodeToError(Yin.error());
+ Result.insert(TC);
+ Yin.nextDocument();
}
+ return Result;
+}
+
+Expected<InstructionBenchmark>
+InstructionBenchmark::readYaml(const LLVMState &State, MemoryBufferRef Buffer) {
+ yaml::Input Yin(Buffer);
+ YamlContext Context(State);
+ InstructionBenchmark Benchmark;
+ if (Yin.setCurrentDocument())
+ yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
+ if (!Context.getLastError().empty())
+ return make_error<Failure>(Context.getLastError());
+ return std::move(Benchmark);
}
Expected<std::vector<InstructionBenchmark>>
-InstructionBenchmark::readYamls(const LLVMState &State, StringRef Filename) {
- if (auto ExpectedMemoryBuffer =
- errorOrToExpected(MemoryBuffer::getFile(Filename, /*IsText=*/true))) {
- yaml::Input Yin(*ExpectedMemoryBuffer.get());
- YamlContext Context(State);
- std::vector<InstructionBenchmark> Benchmarks;
- while (Yin.setCurrentDocument()) {
- Benchmarks.emplace_back();
- yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
- if (Yin.error())
- return errorCodeToError(Yin.error());
- if (!Context.getLastError().empty())
- return make_error<Failure>(Context.getLastError());
- Yin.nextDocument();
- }
- return Benchmarks;
- } else {
- return ExpectedMemoryBuffer.takeError();
+InstructionBenchmark::readYamls(const LLVMState &State,
+ MemoryBufferRef Buffer) {
+ yaml::Input Yin(Buffer);
+ YamlContext Context(State);
+ std::vector<InstructionBenchmark> Benchmarks;
+ while (Yin.setCurrentDocument()) {
+ Benchmarks.emplace_back();
+ yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
+ if (Yin.error())
+ return errorCodeToError(Yin.error());
+ if (!Context.getLastError().empty())
+ return make_error<Failure>(Context.getLastError());
+ Yin.nextDocument();
}
+ return std::move(Benchmarks);
}
Error InstructionBenchmark::writeYamlTo(const LLVMState &State,
@@ -394,25 +394,6 @@
return Error::success();
}
-Error InstructionBenchmark::writeYaml(const LLVMState &State,
- const StringRef Filename) {
- if (Filename == "-") {
- if (auto Err = writeYamlTo(State, outs()))
- return Err;
- } else {
- int ResultFD = 0;
- if (auto E = errorCodeToError(openFileForWrite(Filename, ResultFD,
- sys::fs::CD_CreateAlways,
- sys::fs::OF_TextWithCRLF))) {
- return E;
- }
- raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
- if (auto Err = writeYamlTo(State, Ostr))
- return Err;
- }
- return Error::success();
-}
-
void PerInstructionStats::push(const BenchmarkMeasure &BM) {
if (Key.empty())
Key = BM.Key;
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 436bd00..a2a8095 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -19,10 +19,12 @@
#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"
#include <limits>
+#include <set>
#include <string>
#include <unordered_map>
#include <vector>
@@ -32,6 +34,15 @@
namespace exegesis {
+enum class BenchmarkPhaseSelectorE {
+ PrepareSnippet,
+ PrepareAndAssembleSnippet,
+ AssembleMeasuredCode,
+ Measure,
+};
+
+enum class InstructionBenchmarkFilter { All, RegOnly, WithMem };
+
struct InstructionBenchmarkKey {
// The LLVM opcode name.
std::vector<MCInst> Instructions;
@@ -76,19 +87,40 @@
std::vector<uint8_t> AssembledSnippet;
// How to aggregate measurements.
enum ResultAggregationModeE { Min, Max, Mean, MinVariance };
+
+ InstructionBenchmark() = default;
+ InstructionBenchmark(InstructionBenchmark &&) = default;
+
+ InstructionBenchmark(const InstructionBenchmark &) = delete;
+ InstructionBenchmark &operator=(const InstructionBenchmark &) = delete;
+ InstructionBenchmark &operator=(InstructionBenchmark &&) = delete;
+
// Read functions.
static Expected<InstructionBenchmark> readYaml(const LLVMState &State,
- StringRef Filename);
+ MemoryBufferRef Buffer);
static Expected<std::vector<InstructionBenchmark>>
- readYamls(const LLVMState &State, StringRef Filename);
+ readYamls(const LLVMState &State, MemoryBufferRef Buffer);
+
+ // Given a set of serialized instruction benchmarks, returns the set of
+ // triples and CPUs that appear in the list of benchmarks.
+ struct TripleAndCpu {
+ std::string LLVMTriple;
+ std::string CpuName;
+ bool operator<(const TripleAndCpu &O) const {
+ return std::tie(LLVMTriple, CpuName) < std::tie(O.LLVMTriple, O.CpuName);
+ }
+ };
+ static Expected<std::set<TripleAndCpu>>
+ readTriplesAndCpusFromYamls(MemoryBufferRef Buffer);
class Error readYamlFrom(const LLVMState &State, StringRef InputContent);
// Write functions, non-const because of YAML traits.
+ // NOTE: we intentionally do *NOT* have a variant of this function taking
+ // filename, because it's behaviour is bugprone with regards to
+ // accidentally using it more than once and overriding previous YAML.
class Error writeYamlTo(const LLVMState &State, raw_ostream &S);
-
- class Error writeYaml(const LLVMState &State, const StringRef Filename);
};
bool operator==(const BenchmarkMeasure &A, const BenchmarkMeasure &B);
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 03e7ccc..cc53b00 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -30,8 +30,10 @@
namespace exegesis {
BenchmarkRunner::BenchmarkRunner(const LLVMState &State,
- InstructionBenchmark::ModeE Mode)
- : State(State), Mode(Mode), Scratch(std::make_unique<ScratchSpace>()) {}
+ InstructionBenchmark::ModeE Mode,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector)
+ : State(State), Mode(Mode), BenchmarkPhaseSelector(BenchmarkPhaseSelector),
+ Scratch(std::make_unique<ScratchSpace>()) {}
BenchmarkRunner::~BenchmarkRunner() = default;
@@ -132,11 +134,28 @@
};
} // namespace
-Expected<InstructionBenchmark> BenchmarkRunner::runConfiguration(
+Expected<SmallString<0>> BenchmarkRunner::assembleSnippet(
+ const BenchmarkCode &BC, const SnippetRepetitor &Repetitor,
+ unsigned MinInstructions, unsigned LoopBodySize) const {
+ const std::vector<MCInst> &Instructions = BC.Key.Instructions;
+ SmallString<0> Buffer;
+ raw_svector_ostream OS(Buffer);
+ if (Error E = assembleToStream(
+ State.getExegesisTarget(), State.createTargetMachine(), BC.LiveIns,
+ BC.Key.RegisterInitialValues,
+ Repetitor.Repeat(Instructions, MinInstructions, LoopBodySize), OS)) {
+ return std::move(E);
+ }
+ return Buffer;
+}
+
+Expected<BenchmarkRunner::RunnableConfiguration>
+BenchmarkRunner::getRunnableConfiguration(
const BenchmarkCode &BC, unsigned NumRepetitions, unsigned LoopBodySize,
- ArrayRef<std::unique_ptr<const SnippetRepetitor>> Repetitors,
- bool DumpObjectToDisk) const {
- InstructionBenchmark InstrBenchmark;
+ const SnippetRepetitor &Repetitor) const {
+ RunnableConfiguration RC;
+
+ InstructionBenchmark &InstrBenchmark = RC.InstrBenchmark;
InstrBenchmark.Mode = Mode;
InstrBenchmark.CpuName = std::string(State.getTargetMachine().getTargetCPU());
InstrBenchmark.LLVMTriple =
@@ -148,130 +167,89 @@
InstrBenchmark.Key = BC.Key;
- // If we end up having an error, and we've previously succeeded with
- // some other Repetitor, we want to discard the previous measurements.
- struct ClearBenchmarkOnReturn {
- ClearBenchmarkOnReturn(InstructionBenchmark *IB) : IB(IB) {}
- ~ClearBenchmarkOnReturn() {
- if (Clear)
- IB->Measurements.clear();
- }
- void disarm() { Clear = false; }
-
- private:
- InstructionBenchmark *const IB;
- bool Clear = true;
- };
- ClearBenchmarkOnReturn CBOR(&InstrBenchmark);
-
- for (const std::unique_ptr<const SnippetRepetitor> &Repetitor : Repetitors) {
- // Assemble at least kMinInstructionsForSnippet instructions by repeating
- // the snippet for debug/analysis. This is so that the user clearly
- // understands that the inside instructions are repeated.
+ // Assemble at least kMinInstructionsForSnippet instructions by repeating
+ // the snippet for debug/analysis. This is so that the user clearly
+ // understands that the inside instructions are repeated.
+ if (BenchmarkPhaseSelector > BenchmarkPhaseSelectorE::PrepareSnippet) {
const int MinInstructionsForSnippet = 4 * Instructions.size();
const int LoopBodySizeForSnippet = 2 * Instructions.size();
- {
- SmallString<0> Buffer;
- raw_svector_ostream OS(Buffer);
- if (Error E = assembleToStream(
- State.getExegesisTarget(), State.createTargetMachine(),
- BC.LiveIns, BC.Key.RegisterInitialValues,
- Repetitor->Repeat(Instructions, MinInstructionsForSnippet,
- LoopBodySizeForSnippet),
- OS)) {
- return std::move(E);
- }
- const ExecutableFunction EF(State.createTargetMachine(),
- getObjectFromBuffer(OS.str()));
- const auto FnBytes = EF.getFunctionBytes();
- llvm::append_range(InstrBenchmark.AssembledSnippet, FnBytes);
- }
-
- // Assemble NumRepetitions instructions repetitions of the snippet for
- // measurements.
- const auto Filler = Repetitor->Repeat(
- Instructions, InstrBenchmark.NumRepetitions, LoopBodySize);
-
- object::OwningBinary<object::ObjectFile> ObjectFile;
- if (DumpObjectToDisk) {
- auto ObjectFilePath = writeObjectFile(BC, Filler);
- if (Error E = ObjectFilePath.takeError()) {
- InstrBenchmark.Error = toString(std::move(E));
- return InstrBenchmark;
- }
- outs() << "Check generated assembly with: /usr/bin/objdump -d "
- << *ObjectFilePath << "\n";
- ObjectFile = getObjectFromFile(*ObjectFilePath);
- } else {
- SmallString<0> Buffer;
- raw_svector_ostream OS(Buffer);
- if (Error E = assembleToStream(
- State.getExegesisTarget(), State.createTargetMachine(),
- BC.LiveIns, BC.Key.RegisterInitialValues, Filler, OS)) {
- return std::move(E);
- }
- ObjectFile = getObjectFromBuffer(OS.str());
- }
-
- const FunctionExecutorImpl Executor(State, std::move(ObjectFile),
- Scratch.get());
- auto NewMeasurements = runMeasurements(Executor);
- if (Error E = NewMeasurements.takeError()) {
- if (!E.isA<SnippetCrash>())
- return std::move(E);
- InstrBenchmark.Error = toString(std::move(E));
- return InstrBenchmark;
- }
- assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
- for (BenchmarkMeasure &BM : *NewMeasurements) {
- // Scale the measurements by instruction.
- BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
- // Scale the measurements by snippet.
- BM.PerSnippetValue *= static_cast<double>(Instructions.size()) /
- InstrBenchmark.NumRepetitions;
- }
- if (InstrBenchmark.Measurements.empty()) {
- InstrBenchmark.Measurements = std::move(*NewMeasurements);
- continue;
- }
-
- assert(Repetitors.size() > 1 && !InstrBenchmark.Measurements.empty() &&
- "We're in an 'min' repetition mode, and need to aggregate new "
- "result to the existing result.");
- assert(InstrBenchmark.Measurements.size() == NewMeasurements->size() &&
- "Expected to have identical number of measurements.");
- for (auto I : zip(InstrBenchmark.Measurements, *NewMeasurements)) {
- BenchmarkMeasure &Measurement = std::get<0>(I);
- BenchmarkMeasure &NewMeasurement = std::get<1>(I);
- assert(Measurement.Key == NewMeasurement.Key &&
- "Expected measurements to be symmetric");
-
- Measurement.PerInstructionValue = std::min(
- Measurement.PerInstructionValue, NewMeasurement.PerInstructionValue);
- Measurement.PerSnippetValue =
- std::min(Measurement.PerSnippetValue, NewMeasurement.PerSnippetValue);
- }
+ auto Snippet = assembleSnippet(BC, Repetitor, MinInstructionsForSnippet,
+ LoopBodySizeForSnippet);
+ if (Error E = Snippet.takeError())
+ return std::move(E);
+ const ExecutableFunction EF(State.createTargetMachine(),
+ getObjectFromBuffer(*Snippet));
+ const auto FnBytes = EF.getFunctionBytes();
+ llvm::append_range(InstrBenchmark.AssembledSnippet, FnBytes);
}
- // We successfully measured everything, so don't discard the results.
- CBOR.disarm();
- return InstrBenchmark;
+ // Assemble NumRepetitions instructions repetitions of the snippet for
+ // measurements.
+ if (BenchmarkPhaseSelector > BenchmarkPhaseSelectorE::PrepareAndAssembleSnippet) {
+ auto Snippet = assembleSnippet(BC, Repetitor, InstrBenchmark.NumRepetitions,
+ LoopBodySize);
+ if (Error E = Snippet.takeError())
+ return std::move(E);
+ RC.ObjectFile = getObjectFromBuffer(*Snippet);
+ }
+
+ return std::move(RC);
}
-Expected<std::string>
-BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC,
- const FillFunction &FillFunction) const {
+Expected<InstructionBenchmark>
+BenchmarkRunner::runConfiguration(RunnableConfiguration &&RC,
+ bool DumpObjectToDisk) const {
+ InstructionBenchmark &InstrBenchmark = RC.InstrBenchmark;
+ object::OwningBinary<object::ObjectFile> &ObjectFile = RC.ObjectFile;
+
+ if (DumpObjectToDisk &&
+ BenchmarkPhaseSelector > BenchmarkPhaseSelectorE::PrepareAndAssembleSnippet) {
+ auto ObjectFilePath = writeObjectFile(ObjectFile.getBinary()->getData());
+ if (Error E = ObjectFilePath.takeError()) {
+ InstrBenchmark.Error = toString(std::move(E));
+ return std::move(InstrBenchmark);
+ }
+ outs() << "Check generated assembly with: /usr/bin/objdump -d "
+ << *ObjectFilePath << "\n";
+ }
+
+ if (BenchmarkPhaseSelector < BenchmarkPhaseSelectorE::Measure) {
+ InstrBenchmark.Error = "actual measurements skipped.";
+ return std::move(InstrBenchmark);
+ }
+
+ const FunctionExecutorImpl Executor(State, std::move(ObjectFile),
+ Scratch.get());
+ 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);
+ }
+ assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
+ for (BenchmarkMeasure &BM : *NewMeasurements) {
+ // Scale the measurements by instruction.
+ BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
+ // Scale the measurements by snippet.
+ BM.PerSnippetValue *=
+ static_cast<double>(InstrBenchmark.Key.Instructions.size()) /
+ InstrBenchmark.NumRepetitions;
+ }
+ InstrBenchmark.Measurements = std::move(*NewMeasurements);
+
+ return std::move(InstrBenchmark);
+}
+
+Expected<std::string> BenchmarkRunner::writeObjectFile(StringRef Buffer) const {
int ResultFD = 0;
SmallString<256> ResultPath;
if (Error E = errorCodeToError(
sys::fs::createTemporaryFile("snippet", "o", ResultFD, ResultPath)))
return std::move(E);
raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
- if (Error E = assembleToStream(
- State.getExegesisTarget(), State.createTargetMachine(), BC.LiveIns,
- BC.Key.RegisterInitialValues, FillFunction, OFS)) {
- return std::move(E);
- }
+ OFS.write(Buffer.data(), Buffer.size());
+ OFS.flush();
return std::string(ResultPath.str());
}
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 b66902e..ea60eee 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
@@ -35,15 +35,36 @@
class BenchmarkRunner {
public:
explicit BenchmarkRunner(const LLVMState &State,
- InstructionBenchmark::ModeE Mode);
+ InstructionBenchmark::ModeE Mode,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector);
virtual ~BenchmarkRunner();
- Expected<InstructionBenchmark>
- runConfiguration(const BenchmarkCode &Configuration, unsigned NumRepetitions,
- unsigned LoopUnrollFactor,
- ArrayRef<std::unique_ptr<const SnippetRepetitor>> Repetitors,
- bool DumpObjectToDisk) const;
+ class RunnableConfiguration {
+ friend class BenchmarkRunner;
+
+ public:
+ ~RunnableConfiguration() = default;
+ RunnableConfiguration(RunnableConfiguration &&) = default;
+
+ RunnableConfiguration(const RunnableConfiguration &) = delete;
+ RunnableConfiguration &operator=(RunnableConfiguration &&) = delete;
+ RunnableConfiguration &operator=(const RunnableConfiguration &) = delete;
+
+ private:
+ RunnableConfiguration() = default;
+
+ InstructionBenchmark InstrBenchmark;
+ object::OwningBinary<object::ObjectFile> ObjectFile;
+ };
+
+ Expected<RunnableConfiguration>
+ getRunnableConfiguration(const BenchmarkCode &Configuration,
+ unsigned NumRepetitions, unsigned LoopUnrollFactor,
+ const SnippetRepetitor &Repetitor) const;
+
+ Expected<InstructionBenchmark> runConfiguration(RunnableConfiguration &&RC,
+ bool DumpObjectToDisk) const;
// Scratch space to run instructions that touch memory.
struct ScratchSpace {
@@ -77,13 +98,18 @@
protected:
const LLVMState &State;
const InstructionBenchmark::ModeE Mode;
+ const BenchmarkPhaseSelectorE BenchmarkPhaseSelector;
private:
virtual Expected<std::vector<BenchmarkMeasure>>
runMeasurements(const FunctionExecutor &Executor) const = 0;
- Expected<std::string> writeObjectFile(const BenchmarkCode &Configuration,
- const FillFunction &Fill) const;
+ Expected<SmallString<0>> assembleSnippet(const BenchmarkCode &BC,
+ const SnippetRepetitor &Repetitor,
+ unsigned MinInstructions,
+ unsigned LoopBodySize) const;
+
+ Expected<std::string> writeObjectFile(StringRef Buffer) const;
const std::unique_ptr<ScratchSpace> Scratch;
};
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 2ca0ce4..e495ab3 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
@@ -1,23 +1,23 @@
-set(TARGETS_TO_APPEND "")
+set(LLVM_EXEGESIS_TARGETS)
if (LLVM_TARGETS_TO_BUILD MATCHES "X86")
- add_subdirectory(X86)
- set(TARGETS_TO_APPEND "${TARGETS_TO_APPEND} X86")
+ list(APPEND LLVM_EXEGESIS_TARGETS "X86")
endif()
if (LLVM_TARGETS_TO_BUILD MATCHES "AArch64")
- add_subdirectory(AArch64)
- set(TARGETS_TO_APPEND "${TARGETS_TO_APPEND} AArch64")
+ list(APPEND LLVM_EXEGESIS_TARGETS "AArch64")
endif()
if (LLVM_TARGETS_TO_BUILD MATCHES "PowerPC")
- add_subdirectory(PowerPC)
- set(TARGETS_TO_APPEND "${TARGETS_TO_APPEND} PowerPC")
+ list(APPEND LLVM_EXEGESIS_TARGETS "PowerPC")
endif()
if (LLVM_TARGETS_TO_BUILD MATCHES "Mips")
- add_subdirectory(Mips)
- set(TARGETS_TO_APPEND "${TARGETS_TO_APPEND} Mips")
+ list(APPEND LLVM_EXEGESIS_TARGETS "Mips")
endif()
-set(LLVM_EXEGESIS_TARGETS "${LLVM_EXEGESIS_TARGETS} ${TARGETS_TO_APPEND}" PARENT_SCOPE)
+set(LLVM_EXEGESIS_TARGETS ${LLVM_EXEGESIS_TARGETS} PARENT_SCOPE)
+
+foreach(t ${LLVM_EXEGESIS_TARGETS})
+ add_subdirectory(${t})
+endforeach()
set(LLVM_LINK_COMPONENTS
Analysis
@@ -26,6 +26,7 @@
ExecutionEngine
GlobalISel
MC
+ MCA
MCDisassembler
MCJIT
MCParser
@@ -33,6 +34,7 @@
ObjectYAML
RuntimeDyld
Support
+ TargetParser
)
set(libs)
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 08646aa..f91d6fc 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.cpp
@@ -63,13 +63,13 @@
ArrayRef<size_t> Pts) const {
// First, get the centroid of this group of points. This is O(N).
SchedClassClusterCentroid G;
- for_each(Pts, [this, &G](size_t P) {
+ for (size_t P : Pts) {
assert(P < Points_.size());
ArrayRef<BenchmarkMeasure> Measurements = Points_[P].Measurements;
if (Measurements.empty()) // Error point.
- return;
+ continue;
G.addPoint(Measurements);
- });
+ }
const std::vector<BenchmarkMeasure> Centroid = G.getAsPoint();
// Since we will be comparing with the centroid, we need to halve the epsilon.
@@ -226,9 +226,8 @@
/*IsUnstable=*/!areAllNeighbours(PointsOfSchedClass)));
Cluster &CurrentCluster = Clusters_.back();
// Mark points as belonging to the new cluster.
- for_each(PointsOfSchedClass, [this, &CurrentCluster](size_t P) {
+ for (size_t P : PointsOfSchedClass)
ClusterIdForPoint_[P] = CurrentCluster.Id;
- });
// And add all the points of this opcode's sched class to the new cluster.
CurrentCluster.PointIndices.reserve(PointsOfSchedClass.size());
CurrentCluster.PointIndices.assign(PointsOfSchedClass.begin(),
@@ -315,7 +314,7 @@
// Actually append to-be-moved points to the new cluster.
UnstableCluster.PointIndices.insert(UnstableCluster.PointIndices.end(),
it, OldCluster.PointIndices.end());
- // And finally, remove "to-be-moved" points form the old cluster.
+ // And finally, remove "to-be-moved" points from the old cluster.
OldCluster.PointIndices.erase(it, OldCluster.PointIndices.end());
// Now, the old cluster may end up being empty, but let's just keep it
// in whatever state it ended up. Purging empty clusters isn't worth it.
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.h
index a4da3af..8d8570b 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Clustering.h
@@ -15,7 +15,6 @@
#define LLVM_TOOLS_LLVM_EXEGESIS_CLUSTERING_H
#include "BenchmarkResult.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/Error.h"
#include <limits>
#include <vector>
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
index 9840a08..fd156ee 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
@@ -11,10 +11,19 @@
namespace llvm {
namespace exegesis {
+CodeTemplate::CodeTemplate(const CodeTemplate &) = default;
+
CodeTemplate::CodeTemplate(CodeTemplate &&) = default;
CodeTemplate &CodeTemplate::operator=(CodeTemplate &&) = default;
+CodeTemplate &CodeTemplate::operator=(const CodeTemplate &) = default;
+
+CodeTemplate CodeTemplate::clone() const {
+ CodeTemplate CT = *this;
+ return CT;
+}
+
InstructionTemplate::InstructionTemplate(const Instruction *Instr)
: Instr(Instr), VariableValues(Instr->Variables.size()) {}
@@ -100,7 +109,7 @@
ExecutionMode::ALWAYS_PARALLEL_MISSING_USE_OR_DEF,
ExecutionMode::PARALLEL_VIA_EXPLICIT_REGS,
};
- return makeArrayRef(kAllExecutionModeBits);
+ return ArrayRef(kAllExecutionModeBits);
}
SmallVector<ExecutionMode, 4> getExecutionModeBits(ExecutionMode Execution) {
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
index bea1030..16982f9 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
@@ -119,8 +119,8 @@
CodeTemplate(CodeTemplate &&); // default
CodeTemplate &operator=(CodeTemplate &&); // default
- CodeTemplate(const CodeTemplate &) = delete;
- CodeTemplate &operator=(const CodeTemplate &) = delete;
+
+ CodeTemplate clone() const;
ExecutionMode Execution = ExecutionMode::UNKNOWN;
// See InstructionBenchmarkKey.::Config.
@@ -132,6 +132,13 @@
// If the template uses the provided scratch memory, the register in which
// the pointer to this memory is passed in to the function.
unsigned ScratchSpacePointerInReg = 0;
+
+#if defined(__GNUC__) && (defined(__clang__) || LLVM_GNUC_PREREQ(8, 0, 0))
+ // FIXME: GCC7 bug workaround. Drop #if after GCC7 no longer supported.
+private:
+#endif
+ CodeTemplate(const CodeTemplate &); // default
+ CodeTemplate &operator=(const CodeTemplate &); // default
};
} // 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 6cdefb8..d57ee14 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
@@ -20,8 +20,9 @@
LatencyBenchmarkRunner::LatencyBenchmarkRunner(
const LLVMState &State, InstructionBenchmark::ModeE Mode,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAgg)
- : BenchmarkRunner(State, Mode) {
+ : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector) {
assert((Mode == InstructionBenchmark::Latency ||
Mode == InstructionBenchmark::InverseThroughput) &&
"invalid mode");
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 b9b9efc..d7d1fa9 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
@@ -23,6 +23,7 @@
public:
LatencyBenchmarkRunner(
const LLVMState &State, InstructionBenchmark::ModeE Mode,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAggMode);
~LatencyBenchmarkRunner() override;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
index 26575cc..d7940ce 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
@@ -22,21 +22,65 @@
namespace llvm {
namespace exegesis {
-LLVMState::LLVMState(const std::string &Triple, const std::string &CpuName,
- const std::string &Features) {
+Expected<LLVMState> LLVMState::Create(std::string TripleName,
+ std::string CpuName,
+ const StringRef Features) {
+ if (TripleName.empty())
+ TripleName = Triple::normalize(sys::getDefaultTargetTriple());
+
+ Triple TheTriple(TripleName);
+
+ // Get the target specific parser.
std::string Error;
- const Target *const TheTarget = TargetRegistry::lookupTarget(Triple, Error);
- assert(TheTarget && "unknown target for host");
- const TargetOptions Options;
- TheTargetMachine.reset(
- static_cast<LLVMTargetMachine *>(TheTarget->createTargetMachine(
- Triple, CpuName, Features, Options, Reloc::Model::Static)));
- assert(TheTargetMachine && "unable to create target machine");
- TheExegesisTarget = ExegesisTarget::lookup(TheTargetMachine->getTargetTriple());
- if (!TheExegesisTarget) {
- errs() << "no exegesis target for " << Triple << ", using default\n";
- TheExegesisTarget = &ExegesisTarget::getDefault();
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(/*MArch=*/"", TheTriple, Error);
+ if (!TheTarget) {
+ return llvm::make_error<llvm::StringError>("no LLVM target for triple " +
+ TripleName,
+ llvm::inconvertibleErrorCode());
}
+
+ // Update Triple with the updated triple from the target lookup.
+ TripleName = TheTriple.str();
+
+ if (CpuName == "native")
+ CpuName = std::string(llvm::sys::getHostCPUName());
+
+ std::unique_ptr<MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(TripleName, CpuName, ""));
+ assert(STI && "Unable to create subtarget info!");
+ if (!STI->isCPUStringValid(CpuName)) {
+ return llvm::make_error<llvm::StringError>(Twine("invalid CPU name (")
+ .concat(CpuName)
+ .concat(") for triple ")
+ .concat(TripleName),
+ llvm::inconvertibleErrorCode());
+ }
+ const TargetOptions Options;
+ std::unique_ptr<const TargetMachine> TM(
+ static_cast<LLVMTargetMachine *>(TheTarget->createTargetMachine(
+ TripleName, CpuName, Features, Options, Reloc::Model::Static)));
+ if (!TM) {
+ return llvm::make_error<llvm::StringError>(
+ "unable to create target machine", llvm::inconvertibleErrorCode());
+ }
+
+ const ExegesisTarget *ET =
+ TripleName.empty() ? &ExegesisTarget::getDefault()
+ : ExegesisTarget::lookup(TM->getTargetTriple());
+ if (!ET) {
+ return llvm::make_error<llvm::StringError>(
+ "no Exegesis target for triple " + TripleName,
+ llvm::inconvertibleErrorCode());
+ }
+ return LLVMState(std::move(TM), ET, CpuName);
+}
+
+LLVMState::LLVMState(std::unique_ptr<const TargetMachine> TM,
+ const ExegesisTarget *ET, const StringRef CpuName)
+ : TheExegesisTarget(ET), TheTargetMachine(std::move(TM)),
+ OpcodeNameToOpcodeIdxMapping(createOpcodeNameToOpcodeIdxMapping()),
+ RegNameToRegNoMapping(createRegNameToRegNoMapping()) {
PfmCounters = &TheExegesisTarget->getPfmCounters(CpuName);
BitVector ReservedRegs = getFunctionReservedRegs(getTargetMachine());
@@ -47,10 +91,6 @@
IC.reset(new InstructionsCache(getInstrInfo(), getRATC()));
}
-LLVMState::LLVMState(const std::string &CpuName)
- : LLVMState(sys::getProcessTriple(),
- CpuName.empty() ? sys::getHostCPUName().str() : CpuName, "") {}
-
std::unique_ptr<LLVMTargetMachine> LLVMState::createTargetMachine() const {
return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>(
TheTargetMachine->getTarget().createTargetMachine(
@@ -60,6 +100,30 @@
Reloc::Model::Static)));
}
+std::unique_ptr<const DenseMap<StringRef, unsigned>>
+LLVMState::createOpcodeNameToOpcodeIdxMapping() const {
+ const MCInstrInfo &InstrInfo = getInstrInfo();
+ auto Map = std::make_unique<DenseMap<StringRef, unsigned>>(
+ InstrInfo.getNumOpcodes());
+ for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I)
+ (*Map)[InstrInfo.getName(I)] = I;
+ assert(Map->size() == InstrInfo.getNumOpcodes() && "Size prediction failed");
+ return std::move(Map);
+}
+
+std::unique_ptr<const DenseMap<StringRef, unsigned>>
+LLVMState::createRegNameToRegNoMapping() const {
+ const MCRegisterInfo &RegInfo = getRegInfo();
+ auto Map =
+ std::make_unique<DenseMap<StringRef, unsigned>>(RegInfo.getNumRegs());
+ // Special-case RegNo 0, which would otherwise be spelled as ''.
+ (*Map)[kNoRegister] = 0;
+ for (unsigned I = 1, E = RegInfo.getNumRegs(); I < E; ++I)
+ (*Map)[RegInfo.getName(I)] = I;
+ assert(Map->size() == RegInfo.getNumRegs() && "Size prediction failed");
+ return std::move(Map);
+}
+
bool LLVMState::canAssemble(const MCInst &Inst) const {
MCContext Context(TheTargetMachine->getTargetTriple(),
TheTargetMachine->getMCAsmInfo(),
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 e660a9f..6039bdb 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/LlvmState.h
@@ -16,6 +16,7 @@
#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"
@@ -25,6 +26,8 @@
#include <memory>
#include <string>
+static constexpr llvm::StringLiteral kNoRegister("%noreg");
+
namespace llvm {
namespace exegesis {
@@ -35,12 +38,12 @@
// measurements.
class LLVMState {
public:
- // Uses the host triple. If CpuName is empty, uses the host CPU.
- LLVMState(const std::string &CpuName);
-
- LLVMState(const std::string &Triple,
- const std::string &CpuName,
- const std::string &Features = ""); // For tests.
+ // Factory function.
+ // If `Triple` is empty, uses the host triple.
+ // If `CpuName` is empty, uses the host CPU.
+ // `Features` is intended for tests.
+ static Expected<LLVMState> Create(std::string TripleName, std::string CpuName,
+ StringRef Features = "");
const TargetMachine &getTargetMachine() const { return *TheTargetMachine; }
std::unique_ptr<LLVMTargetMachine> createTargetMachine() const;
@@ -65,12 +68,34 @@
const PfmCountersInfo &getPfmCounters() const { return *PfmCounters; }
+ const DenseMap<StringRef, unsigned> &getOpcodeNameToOpcodeIdxMapping() const {
+ assert(OpcodeNameToOpcodeIdxMapping);
+ return *OpcodeNameToOpcodeIdxMapping;
+ };
+
+ const DenseMap<StringRef, unsigned> &getRegNameToRegNoMapping() const {
+ assert(RegNameToRegNoMapping);
+ return *RegNameToRegNoMapping;
+ }
+
private:
+ std::unique_ptr<const DenseMap<StringRef, unsigned>>
+ createOpcodeNameToOpcodeIdxMapping() const;
+
+ std::unique_ptr<const DenseMap<StringRef, unsigned>>
+ createRegNameToRegNoMapping() const;
+
+ LLVMState(std::unique_ptr<const TargetMachine> TM, const ExegesisTarget *ET,
+ StringRef CpuName);
+
const ExegesisTarget *TheExegesisTarget;
std::unique_ptr<const TargetMachine> TheTargetMachine;
std::unique_ptr<const RegisterAliasingTrackerCache> RATC;
std::unique_ptr<const InstructionsCache> IC;
const PfmCountersInfo *PfmCounters;
+ std::unique_ptr<const DenseMap<StringRef, unsigned>>
+ OpcodeNameToOpcodeIdxMapping;
+ std::unique_ptr<const DenseMap<StringRef, unsigned>> RegNameToRegNoMapping;
};
} // namespace exegesis
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 0ad6645..f453731 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
@@ -67,7 +67,7 @@
unsigned Operand::getImplicitReg() const {
assert(ImplicitReg);
- return *ImplicitReg;
+ return ImplicitReg;
}
const RegisterAliasingTracker &Operand::getRegisterAliasing() const {
@@ -111,7 +111,7 @@
SmallVector<Operand, 8> Operands;
SmallVector<Variable, 4> Variables;
for (; OpIndex < Description->getNumOperands(); ++OpIndex) {
- const auto &OpInfo = Description->opInfo_begin()[OpIndex];
+ const auto &OpInfo = Description->operands()[OpIndex];
Operand Operand;
Operand.Index = OpIndex;
Operand.IsDef = (OpIndex < Description->getNumDefs());
@@ -128,21 +128,19 @@
Operand.Info = &OpInfo;
Operands.push_back(Operand);
}
- for (const MCPhysReg *MCPhysReg = Description->getImplicitDefs();
- MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
+ for (MCPhysReg MCPhysReg : Description->implicit_defs()) {
Operand Operand;
- Operand.Index = OpIndex;
+ Operand.Index = OpIndex++;
Operand.IsDef = true;
- Operand.Tracker = &RATC.getRegister(*MCPhysReg);
+ Operand.Tracker = &RATC.getRegister(MCPhysReg);
Operand.ImplicitReg = MCPhysReg;
Operands.push_back(Operand);
}
- for (const MCPhysReg *MCPhysReg = Description->getImplicitUses();
- MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
+ for (MCPhysReg MCPhysReg : Description->implicit_uses()) {
Operand Operand;
- Operand.Index = OpIndex;
+ Operand.Index = OpIndex++;
Operand.IsDef = false;
- Operand.Tracker = &RATC.getRegister(*MCPhysReg);
+ Operand.Tracker = &RATC.getRegister(MCPhysReg);
Operand.ImplicitReg = MCPhysReg;
Operands.push_back(Operand);
}
@@ -351,10 +349,12 @@
}
AliasingConfigurations::AliasingConfigurations(
- const Instruction &DefInstruction, const Instruction &UseInstruction) {
- if (UseInstruction.AllUseRegs.anyCommon(DefInstruction.AllDefRegs)) {
- auto CommonRegisters = UseInstruction.AllUseRegs;
- CommonRegisters &= DefInstruction.AllDefRegs;
+ const Instruction &DefInstruction, const Instruction &UseInstruction,
+ const BitVector &ForbiddenRegisters) {
+ auto CommonRegisters = UseInstruction.AllUseRegs;
+ CommonRegisters &= DefInstruction.AllDefRegs;
+ CommonRegisters.reset(ForbiddenRegisters);
+ if (!CommonRegisters.empty()) {
for (const MCPhysReg Reg : CommonRegisters.set_bits()) {
AliasingRegisterOperands ARO;
addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs);
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
index 8c7e0b2..f8ebc07 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
@@ -24,7 +24,6 @@
#include "RegisterAliasing.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
@@ -49,7 +48,7 @@
// The index of this Variable in Instruction.Variables and its associated
// Value in InstructionBuilder.VariableValues.
- Optional<uint8_t> Index;
+ std::optional<uint8_t> Index;
};
// MCOperandInfo can only represents Explicit operands. This object gives a
@@ -59,8 +58,7 @@
// registers and the registers reachable from them (aliasing registers).
// - Info: a shortcut for MCInstrDesc::operands()[Index].
// - TiedToIndex: the index of the Operand holding the value or -1.
-// - ImplicitReg: a pointer to the register value when Operand is Implicit,
-// nullptr otherwise.
+// - ImplicitReg: the register value when Operand is Implicit, 0 otherwise.
// - VariableIndex: the index of the Variable holding the value for this Operand
// or -1 if this operand is implicit.
struct Operand {
@@ -82,13 +80,13 @@
const MCOperandInfo &getExplicitOperandInfo() const;
// Please use the accessors above and not the following fields.
- Optional<uint8_t> Index;
+ std::optional<uint8_t> Index;
bool IsDef = false;
const RegisterAliasingTracker *Tracker = nullptr; // Set for Register Op.
const MCOperandInfo *Info = nullptr; // Set for Explicit Op.
- Optional<uint8_t> TiedToIndex; // Set for Reg&Explicit Op.
- const MCPhysReg *ImplicitReg = nullptr; // Set for Implicit Op.
- Optional<uint8_t> VariableIndex; // Set for Explicit Op.
+ std::optional<uint8_t> TiedToIndex; // Set for Reg&Explicit Op.
+ MCPhysReg ImplicitReg = 0; // Non-0 for Implicit Op.
+ std::optional<uint8_t> VariableIndex; // Set for Explicit Op.
};
/// A cache of BitVector to reuse between Instructions.
@@ -218,7 +216,8 @@
// to alias with Use registers of UseInstruction.
struct AliasingConfigurations {
AliasingConfigurations(const Instruction &DefInstruction,
- const Instruction &UseInstruction);
+ const Instruction &UseInstruction,
+ const BitVector &ForbiddenRegisters);
bool empty() const; // True if no aliasing configuration is found.
bool hasImplicitAliasing() const;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/CMakeLists.txt
index ecf6590..99d7034 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Mips/CMakeLists.txt
@@ -8,6 +8,8 @@
Exegesis
Core
Support
+ TargetParser
+ MC
)
add_llvm_library(LLVMExegesisMips
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp b/src/llvm-project/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp
index 7728fcb..114e274 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp
@@ -79,13 +79,12 @@
namespace llvm {
namespace exegesis {
-static SmallVector<const Variable *, 8>
-getVariablesWithTiedOperands(const Instruction &Instr) {
+static bool hasVariablesWithTiedOperands(const Instruction &Instr) {
SmallVector<const Variable *, 8> Result;
for (const auto &Var : Instr.Variables)
if (Var.hasTiedOperands())
- Result.push_back(&Var);
- return Result;
+ return true;
+ return false;
}
ParallelSnippetGenerator::~ParallelSnippetGenerator() = default;
@@ -114,43 +113,181 @@
"not enough scratch space");
}
-static std::vector<InstructionTemplate> generateSnippetUsingStaticRenaming(
- const LLVMState &State, const InstructionTemplate &IT,
- const ArrayRef<const Variable *> TiedVariables,
- const BitVector &ForbiddenRegisters) {
- std::vector<InstructionTemplate> Instructions;
- // Assign registers to variables in a round-robin manner. This is simple but
- // ensures that the most register-constrained variable does not get starved.
- std::vector<BitVector> PossibleRegsForVar;
- for (const Variable *Var : TiedVariables) {
- assert(Var);
- const Operand &Op = IT.getInstr().getPrimaryOperand(*Var);
- assert(Op.isReg());
- BitVector PossibleRegs = Op.getRegisterAliasing().sourceBits();
- remove(PossibleRegs, ForbiddenRegisters);
- PossibleRegsForVar.push_back(std::move(PossibleRegs));
+enum class RegRandomizationStrategy : uint8_t {
+ PickRandomRegs,
+ SingleStaticRegPerOperand,
+ SingleStaticReg,
+
+ FIRST = PickRandomRegs,
+ LAST = SingleStaticReg,
+};
+
+} // namespace exegesis
+
+template <> struct enum_iteration_traits<exegesis::RegRandomizationStrategy> {
+ static constexpr bool is_iterable = true;
+};
+
+namespace exegesis {
+
+const char *getDescription(RegRandomizationStrategy S) {
+ switch (S) {
+ case RegRandomizationStrategy::PickRandomRegs:
+ return "randomizing registers";
+ case RegRandomizationStrategy::SingleStaticRegPerOperand:
+ return "one unique register for each position";
+ case RegRandomizationStrategy::SingleStaticReg:
+ return "reusing the same register for all positions";
}
- SmallVector<int, 2> Iterators(TiedVariables.size(), 0);
- while (true) {
- InstructionTemplate TmpIT = IT;
- // Find a possible register for each variable in turn, marking the
- // register as taken.
- for (size_t VarId = 0; VarId < TiedVariables.size(); ++VarId) {
- const int NextPossibleReg =
- PossibleRegsForVar[VarId].find_next(Iterators[VarId]);
- if (NextPossibleReg <= 0) {
- return Instructions;
- }
- TmpIT.getValueFor(*TiedVariables[VarId]) =
- MCOperand::createReg(NextPossibleReg);
- // Bump iterator.
- Iterators[VarId] = NextPossibleReg;
- // Prevent other variables from using the register.
- for (BitVector &OtherPossibleRegs : PossibleRegsForVar) {
- OtherPossibleRegs.reset(NextPossibleReg);
+ llvm_unreachable("Unknown UseRegRandomizationStrategy enum");
+}
+
+static std::variant<std::nullopt_t, MCOperand, Register>
+generateSingleRegisterForInstrAvoidingDefUseOverlap(
+ const LLVMState &State, const BitVector &ForbiddenRegisters,
+ const BitVector &ImplicitUseAliases, const BitVector &ImplicitDefAliases,
+ const BitVector &Uses, const BitVector &Defs, const InstructionTemplate &IT,
+ const Operand &Op, const ArrayRef<InstructionTemplate> Instructions,
+ RegRandomizationStrategy S) {
+ const Instruction &Instr = IT.getInstr();
+ assert(Op.isReg() && Op.isExplicit() && !Op.isMemory() &&
+ !IT.getValueFor(Op).isValid());
+ assert((!Op.isUse() || !Op.isTied()) &&
+ "Not expecting to see a tied use reg");
+
+ if (Op.isUse()) {
+ switch (S) {
+ case RegRandomizationStrategy::PickRandomRegs:
+ break;
+ case RegRandomizationStrategy::SingleStaticReg:
+ case RegRandomizationStrategy::SingleStaticRegPerOperand: {
+ if (!Instructions.empty())
+ return Instructions.front().getValueFor(Op);
+ if (S != RegRandomizationStrategy::SingleStaticReg)
+ break;
+ BitVector PossibleRegisters = Op.getRegisterAliasing().sourceBits();
+ const BitVector UseAliases = getAliasedBits(State.getRegInfo(), Uses);
+ if (std::optional<int> CommonBit =
+ getFirstCommonBit(PossibleRegisters, UseAliases))
+ return *CommonBit;
+ break;
+ }
+ }
+ }
+
+ BitVector PossibleRegisters = Op.getRegisterAliasing().sourceBits();
+ remove(PossibleRegisters, ForbiddenRegisters);
+
+ if (Op.isDef()) {
+ remove(PossibleRegisters, ImplicitUseAliases);
+ const BitVector UseAliases = getAliasedBits(State.getRegInfo(), Uses);
+ remove(PossibleRegisters, UseAliases);
+ }
+
+ if (Op.isUse()) {
+ remove(PossibleRegisters, ImplicitDefAliases);
+ // NOTE: in general, using same reg for multiple Use's is fine.
+ if (S == RegRandomizationStrategy::SingleStaticRegPerOperand) {
+ const BitVector UseAliases = getAliasedBits(State.getRegInfo(), Uses);
+ remove(PossibleRegisters, UseAliases);
+ }
+ }
+
+ bool IsDefWithTiedUse =
+ Instr.Variables[Op.getVariableIndex()].hasTiedOperands();
+ if (Op.isUse() || IsDefWithTiedUse) {
+ // Now, important bit: if we have used some register for def,
+ // then we can not use that same register for *any* use,
+ // be it either an untied use, or an use tied to a def.
+ // But def-ing same regs is fine, as long as there are no uses!
+ const BitVector DefsAliases = getAliasedBits(State.getRegInfo(), Defs);
+ remove(PossibleRegisters, DefsAliases);
+ }
+
+ if (!PossibleRegisters.any())
+ return std::nullopt;
+
+ return randomBit(PossibleRegisters);
+}
+
+static std::optional<InstructionTemplate>
+generateSingleSnippetForInstrAvoidingDefUseOverlap(
+ const LLVMState &State, const BitVector &ForbiddenRegisters,
+ const BitVector &ImplicitUseAliases, const BitVector &ImplicitDefAliases,
+ BitVector &Uses, BitVector &Defs, InstructionTemplate IT,
+ const ArrayRef<InstructionTemplate> Instructions,
+ RegRandomizationStrategy S) {
+ const Instruction &Instr = IT.getInstr();
+ for (const Operand &Op : Instr.Operands) {
+ if (!Op.isReg() || !Op.isExplicit() || Op.isMemory() ||
+ IT.getValueFor(Op).isValid())
+ continue;
+ assert((!Op.isUse() || !Op.isTied()) && "Will not get tied uses.");
+
+ std::variant<std::nullopt_t, MCOperand, Register> R =
+ generateSingleRegisterForInstrAvoidingDefUseOverlap(
+ State, ForbiddenRegisters, ImplicitUseAliases, ImplicitDefAliases,
+ Uses, Defs, IT, Op, Instructions, S);
+
+ if (std::holds_alternative<std::nullopt_t>(R))
+ return {};
+
+ MCOperand MCOp;
+ if (std::holds_alternative<MCOperand>(R))
+ MCOp = std::get<MCOperand>(R);
+ else {
+ Register RandomReg = std::get<Register>(R);
+ if (Op.isDef())
+ Defs.set(RandomReg);
+ if (Op.isUse())
+ Uses.set(RandomReg);
+ MCOp = MCOperand::createReg(RandomReg);
+ }
+ IT.getValueFor(Op) = MCOp;
+ }
+ return IT;
+}
+
+static std::vector<InstructionTemplate>
+generateSnippetForInstrAvoidingDefUseOverlap(
+ const LLVMState &State, const InstructionTemplate &IT,
+ RegRandomizationStrategy S, const BitVector &ForbiddenRegisters) {
+ // We don't want to accidentally serialize the instruction,
+ // so we must be sure that we don't pick a def that is an implicit use,
+ // or a use that is an implicit def, so record implicit regs now.
+ BitVector ImplicitUses(State.getRegInfo().getNumRegs());
+ BitVector ImplicitDefs(State.getRegInfo().getNumRegs());
+ for (const auto &Op : IT.getInstr().Operands) {
+ if (Op.isReg() && Op.isImplicit() && !Op.isMemory()) {
+ assert(Op.isImplicitReg() && "Not an implicit register operand?");
+ if (Op.isUse())
+ ImplicitUses.set(Op.getImplicitReg());
+ else {
+ assert(Op.isDef() && "Not a use and not a def?");
+ ImplicitDefs.set(Op.getImplicitReg());
}
}
- Instructions.push_back(std::move(TmpIT));
+ }
+ const BitVector ImplicitUseAliases =
+ getAliasedBits(State.getRegInfo(), ImplicitUses);
+ const BitVector ImplicitDefAliases =
+ getAliasedBits(State.getRegInfo(), ImplicitDefs);
+
+ BitVector Defs(State.getRegInfo().getNumRegs());
+ BitVector Uses(State.getRegInfo().getNumRegs());
+ std::vector<InstructionTemplate> Instructions;
+
+ while (true) {
+ std::optional<InstructionTemplate> TmpIT =
+ generateSingleSnippetForInstrAvoidingDefUseOverlap(
+ State, ForbiddenRegisters, ImplicitUseAliases, ImplicitDefAliases,
+ Uses, Defs, IT, Instructions, S);
+ if (!TmpIT)
+ return Instructions;
+ Instructions.push_back(std::move(*TmpIT));
+ if (!hasVariablesWithTiedOperands(IT.getInstr()))
+ return Instructions;
+ assert(Instructions.size() <= 128 && "Stuck in endless loop?");
}
}
@@ -164,7 +301,7 @@
? State.getExegesisTarget().getScratchMemoryRegister(
State.getTargetMachine().getTargetTriple())
: 0;
- const AliasingConfigurations SelfAliasing(Instr, Instr);
+ const AliasingConfigurations SelfAliasing(Instr, Instr, ForbiddenRegisters);
if (SelfAliasing.empty()) {
CT.Info = "instruction is parallel, repeating a random one.";
CT.Instructions.push_back(std::move(Variant));
@@ -177,78 +314,41 @@
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
return getSingleton(std::move(CT));
}
- const auto TiedVariables = getVariablesWithTiedOperands(Instr);
- if (!TiedVariables.empty()) {
- CT.Info = "instruction has tied variables, using static renaming.";
- CT.Instructions = generateSnippetUsingStaticRenaming(
- State, Variant, TiedVariables, ForbiddenRegisters);
- instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
- return getSingleton(std::move(CT));
+ std::vector<CodeTemplate> Result;
+ bool HasTiedOperands = hasVariablesWithTiedOperands(Instr);
+ // If there are no tied operands, then we don't want to "saturate backedge",
+ // and the template we will produce will have only a single instruction.
+ unsigned NumUntiedUseRegs = count_if(Instr.Operands, [](const Operand &Op) {
+ return Op.isReg() && Op.isExplicit() && !Op.isMemory() && Op.isUse() &&
+ !Op.isTied();
+ });
+ SmallVector<RegRandomizationStrategy, 3> Strategies;
+ if (HasTiedOperands || NumUntiedUseRegs >= 3)
+ Strategies.push_back(RegRandomizationStrategy::PickRandomRegs);
+ if (NumUntiedUseRegs >= 2)
+ Strategies.push_back(RegRandomizationStrategy::SingleStaticRegPerOperand);
+ Strategies.push_back(RegRandomizationStrategy::SingleStaticReg);
+ for (RegRandomizationStrategy S : Strategies) {
+ CodeTemplate CurrCT = CT.clone();
+ CurrCT.Info =
+ Twine("instruction has ")
+ .concat(HasTiedOperands ? "" : "no ")
+ .concat("tied variables, avoiding "
+ "Read-After-Write issue, picking random def and use "
+ "registers not aliasing each other, for uses, ")
+ .concat(getDescription(S))
+ .str();
+ CurrCT.Instructions = generateSnippetForInstrAvoidingDefUseOverlap(
+ State, Variant, S, ForbiddenRegisters);
+ if (CurrCT.Instructions.empty())
+ return make_error<StringError>(
+ Twine("Failed to produce any snippet via: ").concat(CurrCT.Info),
+ inconvertibleErrorCode());
+ instantiateMemoryOperands(CurrCT.ScratchSpacePointerInReg,
+ CurrCT.Instructions);
+ Result.push_back(std::move(CurrCT));
}
- // No tied variables, we pick random values for defs.
-
- // We don't want to accidentally serialize the instruction,
- // so we must be sure that we don't pick a def that is an implicit use,
- // or a use that is an implicit def, so record implicit regs now.
- BitVector ImplicitUses(State.getRegInfo().getNumRegs());
- BitVector ImplicitDefs(State.getRegInfo().getNumRegs());
- for (const auto &Op : Instr.Operands) {
- if (Op.isReg() && Op.isImplicit() && !Op.isMemory()) {
- assert(Op.isImplicitReg() && "Not an implicit register operand?");
- if (Op.isUse())
- ImplicitUses.set(Op.getImplicitReg());
- else {
- assert(Op.isDef() && "Not a use and not a def?");
- ImplicitDefs.set(Op.getImplicitReg());
- }
- }
- }
- const auto ImplicitUseAliases =
- getAliasedBits(State.getRegInfo(), ImplicitUses);
- const auto ImplicitDefAliases =
- getAliasedBits(State.getRegInfo(), ImplicitDefs);
- BitVector Defs(State.getRegInfo().getNumRegs());
- for (const auto &Op : Instr.Operands) {
- if (Op.isReg() && Op.isExplicit() && Op.isDef() && !Op.isMemory()) {
- auto PossibleRegisters = Op.getRegisterAliasing().sourceBits();
- // Do not use forbidden registers and regs that are implicitly used.
- // Note that we don't try to avoid using implicit defs explicitly.
- remove(PossibleRegisters, ForbiddenRegisters);
- remove(PossibleRegisters, ImplicitUseAliases);
- if (!PossibleRegisters.any())
- return make_error<StringError>(
- Twine("no available registers:\ncandidates:\n")
- .concat(debugString(State.getRegInfo(),
- Op.getRegisterAliasing().sourceBits()))
- .concat("\nforbidden:\n")
- .concat(debugString(State.getRegInfo(), ForbiddenRegisters))
- .concat("\nimplicit use:\n")
- .concat(debugString(State.getRegInfo(), ImplicitUseAliases)),
- inconvertibleErrorCode());
- const auto RandomReg = randomBit(PossibleRegisters);
- Defs.set(RandomReg);
- Variant.getValueFor(Op) = MCOperand::createReg(RandomReg);
- }
- }
- // And pick random use values that are not reserved and don't alias with defs.
- // Note that we don't try to avoid using implicit uses explicitly.
- const auto DefAliases = getAliasedBits(State.getRegInfo(), Defs);
- for (const auto &Op : Instr.Operands) {
- if (Op.isReg() && Op.isExplicit() && Op.isUse() && !Op.isMemory()) {
- auto PossibleRegisters = Op.getRegisterAliasing().sourceBits();
- remove(PossibleRegisters, ForbiddenRegisters);
- remove(PossibleRegisters, DefAliases);
- remove(PossibleRegisters, ImplicitDefAliases);
- assert(PossibleRegisters.any() && "No register left to choose from");
- const auto RandomReg = randomBit(PossibleRegisters);
- Variant.getValueFor(Op) = MCOperand::createReg(RandomReg);
- }
- }
- CT.Info =
- "instruction has no tied variables picking Uses different from defs";
- CT.Instructions.push_back(std::move(Variant));
- instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
- return getSingleton(std::move(CT));
+ return Result;
}
constexpr const size_t ParallelSnippetGenerator::kMinNumDifferentAddresses;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/CMakeLists.txt
index 29e7f57..9483844 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/PowerPC/CMakeLists.txt
@@ -8,6 +8,8 @@
Exegesis
Core
Support
+ TargetParser
+ MC
)
add_llvm_library(LLVMExegesisPowerPC
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/ProgressMeter.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/ProgressMeter.h
new file mode 100644
index 0000000..0cbc3ed
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/ProgressMeter.h
@@ -0,0 +1,145 @@
+//===-- ProgressMeter.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_PROGRESSMETER_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_PROGRESSMETER_H
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <chrono>
+#include <cmath>
+#include <optional>
+#include <type_traits>
+
+namespace llvm {
+namespace exegesis {
+
+/// Represents `\sum_{i=1..accumulated}{step_i} / accumulated`,
+/// where `step_i` is the value passed to the `i`-th call to `step()`,
+/// and `accumulated` is the total number of calls to `step()`.
+template <typename NumTy, typename DenTy = int> class SimpleMovingAverage {
+ NumTy Accumulated = NumTy(0);
+ DenTy Steps = 0;
+
+public:
+ SimpleMovingAverage() = default;
+
+ SimpleMovingAverage(const SimpleMovingAverage &) = delete;
+ SimpleMovingAverage(SimpleMovingAverage &&) = delete;
+ SimpleMovingAverage &operator=(const SimpleMovingAverage &) = delete;
+ SimpleMovingAverage &operator=(SimpleMovingAverage &&) = delete;
+
+ inline void step(NumTy Quantity) {
+ Accumulated += Quantity;
+ ++Steps;
+ }
+
+ inline NumTy getAccumulated() const { return Accumulated; }
+
+ inline DenTy getNumSteps() const { return Steps; }
+
+ template <typename AvgTy = NumTy>
+ inline std::optional<AvgTy> getAverage() const {
+ if (Steps == 0)
+ return std::nullopt;
+ return AvgTy(Accumulated) / Steps;
+ }
+};
+
+template <typename ClockTypeTy = std::chrono::steady_clock,
+ typename = std::enable_if_t<ClockTypeTy::is_steady>>
+class ProgressMeter {
+public:
+ using ClockType = ClockTypeTy;
+ using TimePointType = std::chrono::time_point<ClockType>;
+ using DurationType = std::chrono::duration<typename ClockType::rep,
+ typename ClockType::period>;
+ using CompetionPercentage = int;
+ using Sec = std::chrono::duration<double, std::chrono::seconds::period>;
+
+private:
+ raw_ostream &Out;
+ const int NumStepsTotal;
+ SimpleMovingAverage<DurationType> ElapsedTotal;
+
+public:
+ friend class ProgressMeterStep;
+ class ProgressMeterStep {
+ ProgressMeter *P;
+ const TimePointType Begin;
+
+ public:
+ inline ProgressMeterStep(ProgressMeter *P_)
+ : P(P_), Begin(P ? ProgressMeter<ClockType>::ClockType::now()
+ : TimePointType()) {}
+
+ inline ~ProgressMeterStep() {
+ if (!P)
+ return;
+ const TimePointType End = ProgressMeter<ClockType>::ClockType::now();
+ P->step(End - Begin);
+ }
+
+ ProgressMeterStep(const ProgressMeterStep &) = delete;
+ ProgressMeterStep(ProgressMeterStep &&) = delete;
+ ProgressMeterStep &operator=(const ProgressMeterStep &) = delete;
+ ProgressMeterStep &operator=(ProgressMeterStep &&) = delete;
+ };
+
+ ProgressMeter(int NumStepsTotal_, raw_ostream &out_ = llvm::errs())
+ : Out(out_), NumStepsTotal(NumStepsTotal_) {
+ assert(NumStepsTotal > 0 && "No steps are planned?");
+ }
+
+ ProgressMeter(const ProgressMeter &) = delete;
+ ProgressMeter(ProgressMeter &&) = delete;
+ ProgressMeter &operator=(const ProgressMeter &) = delete;
+ ProgressMeter &operator=(ProgressMeter &&) = delete;
+
+private:
+ void step(DurationType Elapsed) {
+ assert((ElapsedTotal.getNumSteps() < NumStepsTotal) && "Step overflow!");
+ assert(Elapsed.count() >= 0 && "Negative time drift detected.");
+
+ auto [OldProgress, OldEta] = eta();
+ ElapsedTotal.step(Elapsed);
+ auto [NewProgress, NewEta] = eta();
+
+ if (NewProgress < OldProgress + 1)
+ return;
+
+ Out << format("Processing... %*d%%", 3, NewProgress);
+ if (NewEta) {
+ int SecondsTotal = std::ceil(NewEta->count());
+ int Seconds = SecondsTotal % 60;
+ int MinutesTotal = SecondsTotal / 60;
+
+ Out << format(", ETA %02d:%02d", MinutesTotal, Seconds);
+ }
+ Out << "\n";
+ Out.flush();
+ }
+
+ inline std::pair<CompetionPercentage, std::optional<Sec>> eta() const {
+ CompetionPercentage Progress =
+ (100 * ElapsedTotal.getNumSteps()) / NumStepsTotal;
+
+ std::optional<Sec> ETA;
+ if (std::optional<Sec> AverageStepDuration =
+ ElapsedTotal.template getAverage<Sec>())
+ ETA = (NumStepsTotal - ElapsedTotal.getNumSteps()) * *AverageStepDuration;
+
+ return {Progress, ETA};
+ }
+};
+
+} // namespace exegesis
+} // namespace llvm
+
+#endif
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 03386cf..6ed327f 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
@@ -10,6 +10,7 @@
#include "BenchmarkResult.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MCA/Support.h"
#include "llvm/Support/FormatVariadic.h"
#include <limits>
#include <unordered_set>
@@ -45,7 +46,7 @@
//
// Note that in this case, P016 does not contribute any cycles, so it would
// be removed by this function.
-// FIXME: Move this to MCSubtargetInfo and use it in llvm-mca.
+// FIXME: Merge this with the equivalent in llvm-mca.
static SmallVector<MCWriteProcResEntry, 8>
getNonRedundantWriteProcRes(const MCSchedClassDesc &SCDesc,
const MCSubtargetInfo &STI) {
@@ -53,12 +54,33 @@
const auto &SM = STI.getSchedModel();
const unsigned NumProcRes = SM.getNumProcResourceKinds();
- // This assumes that the ProcResDescs are sorted in topological order, which
- // is guaranteed by the tablegen backend.
- SmallVector<float, 32> ProcResUnitUsage(NumProcRes);
+ // Collect resource masks.
+ SmallVector<uint64_t> ProcResourceMasks(NumProcRes);
+ mca::computeProcResourceMasks(SM, ProcResourceMasks);
+
+ // Sort entries by smaller resources for (basic) topological ordering.
+ using ResourceMaskAndEntry = std::pair<uint64_t, const MCWriteProcResEntry *>;
+ SmallVector<ResourceMaskAndEntry, 8> ResourceMaskAndEntries;
for (const auto *WPR = STI.getWriteProcResBegin(&SCDesc),
*const WPREnd = STI.getWriteProcResEnd(&SCDesc);
WPR != WPREnd; ++WPR) {
+ uint64_t Mask = ProcResourceMasks[WPR->ProcResourceIdx];
+ ResourceMaskAndEntries.push_back({Mask, WPR});
+ }
+ sort(ResourceMaskAndEntries,
+ [](const ResourceMaskAndEntry &A, const ResourceMaskAndEntry &B) {
+ unsigned popcntA = llvm::popcount(A.first);
+ unsigned popcntB = llvm::popcount(B.first);
+ if (popcntA < popcntB)
+ return true;
+ if (popcntA > popcntB)
+ return false;
+ return A.first < B.first;
+ });
+
+ SmallVector<float, 32> ProcResUnitUsage(NumProcRes);
+ for (const ResourceMaskAndEntry &Entry : ResourceMaskAndEntries) {
+ const MCWriteProcResEntry *WPR = Entry.second;
const MCProcResourceDesc *const ProcResDesc =
SM.getProcResource(WPR->ProcResourceIdx);
if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
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 962136a..07a009c 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
@@ -96,7 +96,7 @@
switch (ExecutionModeBit) {
case ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS:
// Nothing to do, the instruction is always serial.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS: {
// Picking whatever value for the tied variable will make the instruction
// serial.
@@ -115,8 +115,8 @@
case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
// Making the execution of this instruction serial by selecting one def
// register to alias with one use register.
- const AliasingConfigurations SelfAliasing(Variant.getInstr(),
- Variant.getInstr());
+ const AliasingConfigurations SelfAliasing(
+ Variant.getInstr(), Variant.getInstr(), ForbiddenRegisters);
assert(!SelfAliasing.empty() && !SelfAliasing.hasImplicitAliasing() &&
"Instr must alias itself explicitly");
// This is a self aliasing instruction so defs and uses are from the same
@@ -134,8 +134,9 @@
// Select back-to-back non-memory instruction.
for (const auto *OtherInstr : computeAliasingInstructions(
State, &Instr, kMaxAliasingInstructions, ForbiddenRegisters)) {
- const AliasingConfigurations Forward(Instr, *OtherInstr);
- const AliasingConfigurations Back(*OtherInstr, Instr);
+ const AliasingConfigurations Forward(Instr, *OtherInstr,
+ ForbiddenRegisters);
+ const AliasingConfigurations Back(*OtherInstr, Instr, ForbiddenRegisters);
InstructionTemplate ThisIT(Variant);
InstructionTemplate OtherIT(OtherInstr);
if (!Forward.hasImplicitAliasing())
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 1bcbbcb..0b69a79 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -29,10 +29,10 @@
// An MCStreamer that reads a BenchmarkCode definition from a file.
class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
public:
- explicit BenchmarkCodeStreamer(MCContext *Context,
- const MCRegisterInfo *TheRegInfo,
- BenchmarkCode *Result)
- : MCStreamer(*Context), RegInfo(TheRegInfo), Result(Result) {}
+ explicit BenchmarkCodeStreamer(
+ MCContext *Context, const DenseMap<StringRef, unsigned> &RegNameToRegNo,
+ BenchmarkCode *Result)
+ : MCStreamer(*Context), RegNameToRegNo(RegNameToRegNo), Result(Result) {}
// Implementation of the MCStreamer interface. We only care about
// instructions.
@@ -89,28 +89,25 @@
private:
// We only care about instructions, we don't implement this part of the API.
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- unsigned ByteAlignment) override {}
+ Align ByteAlignment) override {}
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
return false;
}
- void emitValueToAlignment(unsigned ByteAlignment, int64_t Value,
- unsigned ValueSize,
+ void emitValueToAlignment(Align Alignment, int64_t Value, unsigned ValueSize,
unsigned MaxBytesToEmit) override {}
void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
- unsigned ByteAlignment, SMLoc Loc) override {}
+ Align ByteAlignment, SMLoc Loc) override {}
unsigned findRegisterByName(const StringRef RegName) const {
- // FIXME: Can we do better than this ?
- for (unsigned I = 0, E = RegInfo->getNumRegs(); I < E; ++I) {
- if (RegName == RegInfo->getName(I))
- return I;
- }
+ auto Iter = RegNameToRegNo.find(RegName);
+ if (Iter != RegNameToRegNo.end())
+ return Iter->second;
errs() << "'" << RegName
<< "' is not a valid register name for the target\n";
return 0;
}
- const MCRegisterInfo *const RegInfo;
+ const DenseMap<StringRef, unsigned> &RegNameToRegNo;
BenchmarkCode *const Result;
unsigned InvalidComments = 0;
};
@@ -138,7 +135,8 @@
TM.getTarget().createMCObjectFileInfo(Context, /*PIC=*/false));
Context.setObjectFileInfo(ObjectFileInfo.get());
Context.initInlineSourceManager();
- BenchmarkCodeStreamer Streamer(&Context, TM.getMCRegisterInfo(), &Result);
+ BenchmarkCodeStreamer Streamer(&Context, State.getRegNameToRegNoMapping(),
+ &Result);
std::string Error;
raw_string_ostream ErrorStream(Error);
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 b3a7118..4b47be0 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
@@ -75,6 +75,7 @@
{
BenchmarkCode BC;
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;
@@ -140,9 +141,10 @@
}
Expected<std::vector<CodeTemplate>>
-generateSelfAliasingCodeTemplates(InstructionTemplate Variant) {
- const AliasingConfigurations SelfAliasing(Variant.getInstr(),
- Variant.getInstr());
+generateSelfAliasingCodeTemplates(InstructionTemplate Variant,
+ const BitVector &ForbiddenRegisters) {
+ const AliasingConfigurations SelfAliasing(
+ Variant.getInstr(), Variant.getInstr(), ForbiddenRegisters);
if (SelfAliasing.empty())
return make_error<SnippetGeneratorFailure>("empty self aliasing");
std::vector<CodeTemplate> Result;
@@ -213,6 +215,15 @@
return *Itr;
}
+std::optional<int> getFirstCommonBit(const BitVector &A, const BitVector &B) {
+ BitVector Intersect = A;
+ Intersect &= B;
+ int idx = Intersect.find_first();
+ if (idx != -1)
+ return idx;
+ return {};
+}
+
void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
InstructionTemplate &DefIB, InstructionTemplate &UseIB) {
assert(!AliasingConfigurations.empty());
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 7a53c03..9c64d46 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h
@@ -35,7 +35,8 @@
// Generates code templates that has a self-dependency.
Expected<std::vector<CodeTemplate>>
-generateSelfAliasingCodeTemplates(InstructionTemplate Variant);
+generateSelfAliasingCodeTemplates(InstructionTemplate Variant,
+ const BitVector &ForbiddenRegisters);
// Generates code templates without assignment constraints.
Expected<std::vector<CodeTemplate>>
@@ -92,6 +93,9 @@
// Precondition: Vector must have at least one bit set.
size_t randomBit(const BitVector &Vector);
+// Picks a first bit that is common to these two vectors.
+std::optional<int> getFirstCommonBit(const BitVector &A, const BitVector &B);
+
// Picks a random configuration, then selects a random def and a random use from
// it and finally set the selected values in the provided InstructionInstances.
void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
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 1851cb4..bf05131 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp
@@ -60,6 +60,17 @@
LoopBodySize](FunctionFiller &Filler) {
const auto &ET = State.getExegesisTarget();
auto Entry = Filler.getEntry();
+
+ // We can not use loop snippet repetitor for terminator instructions.
+ for (const MCInst &Inst : Instructions) {
+ const unsigned Opcode = Inst.getOpcode();
+ const MCInstrDesc &MCID = Filler.MCII->get(Opcode);
+ if (!MCID.isTerminator())
+ continue;
+ Entry.addReturn();
+ return;
+ }
+
auto Loop = Filler.addBasicBlock();
auto Exit = Filler.addBasicBlock();
@@ -81,13 +92,17 @@
// Set up the loop basic block.
Entry.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
Loop.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
- // The live ins are: the loop counter, the registers that were setup by
- // the entry block, and entry block live ins.
- Loop.MBB->addLiveIn(LoopCounter);
- for (unsigned Reg : Filler.getRegistersSetUp())
- Loop.MBB->addLiveIn(Reg);
- for (const auto &LiveIn : Entry.MBB->liveins())
- Loop.MBB->addLiveIn(LiveIn);
+ // If the snippet setup completed, then we can track liveness.
+ if (Loop.MF.getProperties().hasProperty(
+ MachineFunctionProperties::Property::TracksLiveness)) {
+ // The live ins are: the loop counter, the registers that were setup by
+ // the entry block, and entry block live ins.
+ Loop.MBB->addLiveIn(LoopCounter);
+ for (unsigned Reg : Filler.getRegistersSetUp())
+ Loop.MBB->addLiveIn(Reg);
+ for (const auto &LiveIn : Entry.MBB->liveins())
+ Loop.MBB->addLiveIn(LiveIn);
+ }
for (auto _ : seq(0U, 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 9ff19d5..f226015 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp
@@ -17,6 +17,10 @@
namespace llvm {
namespace exegesis {
+cl::OptionCategory Options("llvm-exegesis options");
+cl::OptionCategory BenchmarkOptions("llvm-exegesis benchmark options");
+cl::OptionCategory AnalysisOptions("llvm-exegesis analysis options");
+
ExegesisTarget::~ExegesisTarget() {} // anchor.
static ExegesisTarget *FirstTarget = nullptr;
@@ -70,6 +74,7 @@
Expected<std::unique_ptr<BenchmarkRunner>>
ExegesisTarget::createBenchmarkRunner(
InstructionBenchmark::ModeE Mode, const LLVMState &State,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAggMode) const {
PfmCountersInfo PfmCounters = State.getPfmCounters();
switch (Mode) {
@@ -77,21 +82,30 @@
return nullptr;
case InstructionBenchmark::Latency:
case InstructionBenchmark::InverseThroughput:
- if (!PfmCounters.CycleCounter) {
+ if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
+ !PfmCounters.CycleCounter) {
const char *ModeName = Mode == InstructionBenchmark::Latency
? "latency"
: "inverse_throughput";
return make_error<Failure>(
Twine("can't run '")
.concat(ModeName)
- .concat("' mode, sched model does not define a cycle counter."));
+ .concat(
+ "' mode, sched model does not define a cycle counter. You "
+ "can pass --skip-measurements to skip the actual "
+ "benchmarking."));
}
- return createLatencyBenchmarkRunner(State, Mode, ResultAggMode);
+ return createLatencyBenchmarkRunner(State, Mode, BenchmarkPhaseSelector,
+ ResultAggMode);
case InstructionBenchmark::Uops:
- if (!PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
- return make_error<Failure>("can't run 'uops' mode, sched model does not "
- "define uops or issue counters.");
- return createUopsBenchmarkRunner(State, ResultAggMode);
+ if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
+ !PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
+ return make_error<Failure>(
+ "can't run 'uops' mode, sched model does not define uops or issue "
+ "counters. You can pass --skip-measurements to skip the actual "
+ "benchmarking.");
+ return createUopsBenchmarkRunner(State, BenchmarkPhaseSelector,
+ ResultAggMode);
}
return nullptr;
}
@@ -108,14 +122,16 @@
std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(
const LLVMState &State, InstructionBenchmark::ModeE Mode,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAggMode) const {
- return std::make_unique<LatencyBenchmarkRunner>(State, Mode, ResultAggMode);
+ return std::make_unique<LatencyBenchmarkRunner>(
+ State, Mode, BenchmarkPhaseSelector, ResultAggMode);
}
std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner(
- const LLVMState &State,
+ const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE /*unused*/) const {
- return std::make_unique<UopsBenchmarkRunner>(State);
+ return std::make_unique<UopsBenchmarkRunner>(State, BenchmarkPhaseSelector);
}
static_assert(std::is_pod<PfmCountersInfo>::value,
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 28c103a..c922228 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/Target.h
@@ -28,11 +28,16 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace exegesis {
+extern cl::OptionCategory Options;
+extern cl::OptionCategory BenchmarkOptions;
+extern cl::OptionCategory AnalysisOptions;
+
struct PfmCountersInfo {
// An optional name of a performance counter that can be used to measure
// cycles.
@@ -155,6 +160,7 @@
// Creates a benchmark runner for the given mode.
Expected<std::unique_ptr<BenchmarkRunner>> createBenchmarkRunner(
InstructionBenchmark::ModeE Mode, const LLVMState &State,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAggMode =
InstructionBenchmark::Min) const;
@@ -193,9 +199,10 @@
const LLVMState &State, const SnippetGenerator::Options &Opts) const;
std::unique_ptr<BenchmarkRunner> virtual createLatencyBenchmarkRunner(
const LLVMState &State, InstructionBenchmark::ModeE Mode,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAggMode) const;
std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner(
- const LLVMState &State,
+ const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
InstructionBenchmark::ResultAggregationModeE ResultAggMode) const;
const ExegesisTarget *Next = nullptr;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/TargetSelect.h b/src/llvm-project/llvm/tools/llvm-exegesis/lib/TargetSelect.h
index 003d12e..c8c6a1c 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/TargetSelect.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/TargetSelect.h
@@ -8,30 +8,26 @@
///
/// \file
///
-/// Utilities to handle the creation of the native exegesis target.
+/// Utilities to handle the creation of the enabled exegesis target(s).
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_EXEGESIS_TARGET_SELECT_H
#define LLVM_TOOLS_LLVM_EXEGESIS_TARGET_SELECT_H
+#include "llvm/Config/llvm-config.h"
+
namespace llvm {
namespace exegesis {
-#ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET
-void LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
-#endif
+// Forward declare all of the initialize methods for targets compiled in
+#define LLVM_EXEGESIS(TargetName) void Initialize##TargetName##ExegesisTarget();
+#include "llvm/Config/TargetExegesis.def"
-// Initializes the native exegesis target, or returns false if there is no
-// native target (either because llvm-exegesis does not support the target or
-// because it's not linked in).
-inline bool InitializeNativeExegesisTarget() {
-#ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET
- LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
- return true;
-#else
- return false;
-#endif
+// Initializes all exegesis targets compiled in.
+inline void InitializeAllExegesisTargets() {
+#define LLVM_EXEGESIS(TargetName) Initialize##TargetName##ExegesisTarget();
+#include "llvm/Config/TargetExegesis.def"
}
} // namespace exegesis
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 cda74eb..c726944 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
@@ -21,8 +21,10 @@
class UopsBenchmarkRunner : public BenchmarkRunner {
public:
- UopsBenchmarkRunner(const LLVMState &State)
- : BenchmarkRunner(State, InstructionBenchmark::Uops) {}
+ UopsBenchmarkRunner(const LLVMState &State,
+ BenchmarkPhaseSelectorE BenchmarkPhaseSelector)
+ : BenchmarkRunner(State, InstructionBenchmark::Uops,
+ BenchmarkPhaseSelector) {}
~UopsBenchmarkRunner() override;
static constexpr const size_t kMinNumDifferentAddresses = 6;
diff --git a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/CMakeLists.txt
index da30b9b..1e74109 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/lib/X86/CMakeLists.txt
@@ -8,7 +8,9 @@
Exegesis
Core
Support
+ TargetParser
CodeGen
+ MC
)
add_llvm_library(LLVMExegesisX86
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 2f82759..6c9f4d5 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
@@ -38,9 +38,6 @@
namespace llvm {
namespace exegesis {
-static cl::OptionCategory
- BenchmarkOptions("llvm-exegesis benchmark x86-options");
-
// If a positive value is specified, we are going to use the LBR in
// latency-mode.
//
@@ -54,6 +51,11 @@
cl::desc("The sample period (nbranches/sample), used for LBR sampling"),
cl::cat(BenchmarkOptions), cl::init(0));
+static cl::opt<bool>
+ DisableUpperSSERegisters("x86-disable-upper-sse-registers",
+ cl::desc("Disable XMM8-XMM15 register usage"),
+ cl::cat(BenchmarkOptions), cl::init(false));
+
// FIXME: Validates that repetition-mode is loop if LBR is requested.
// Returns a non-null reason if we cannot handle the memory references in this
@@ -212,6 +214,8 @@
case X86::LSS32rm:
case X86::LSS64rm:
case X86::SYSENTER:
+ case X86::WRFSBASE:
+ case X86::WRFSBASE64:
return "unsupported opcode";
default:
break;
@@ -363,7 +367,7 @@
// - `ST(0) = fsqrt(ST(0))` (OneArgFPRW)
// - `ST(0) = ST(0) + ST(i)` (TwoArgFP)
// They are intrinsically serial and do not modify the state of the stack.
- return generateSelfAliasingCodeTemplates(Variant);
+ return generateSelfAliasingCodeTemplates(Variant, ForbiddenRegisters);
default:
llvm_unreachable("Unknown FP Type!");
}
@@ -419,7 +423,7 @@
// - `ST(0) = ST(0) + ST(i)` (TwoArgFP)
// They are intrinsically serial and do not modify the state of the stack.
// We generate the same code for latency and uops.
- return generateSelfAliasingCodeTemplates(Variant);
+ return generateSelfAliasingCodeTemplates(Variant, ForbiddenRegisters);
case X86II::CompareFP:
case X86II::CondMovFP:
// We can compute uops for any FP instruction that does not grow or shrink
@@ -708,9 +712,12 @@
const APInt &Value) const override;
ArrayRef<unsigned> getUnavailableRegisters() const override {
- return makeArrayRef(kUnavailableRegisters,
- sizeof(kUnavailableRegisters) /
- sizeof(kUnavailableRegisters[0]));
+ if (DisableUpperSSERegisters)
+ return ArrayRef(kUnavailableRegistersSSE,
+ sizeof(kUnavailableRegistersSSE) /
+ sizeof(kUnavailableRegistersSSE[0]));
+
+ return ArrayRef(kUnavailableRegisters, std::size(kUnavailableRegisters));
}
bool allowAsBackToBack(const Instruction &Instr) const override {
@@ -773,6 +780,7 @@
}
static const unsigned kUnavailableRegisters[4];
+ static const unsigned kUnavailableRegistersSSE[12];
};
// We disable a few registers that cannot be encoded on instructions with a REX
@@ -780,6 +788,12 @@
const unsigned ExegesisX86Target::kUnavailableRegisters[4] = {X86::AH, X86::BH,
X86::CH, X86::DH};
+// Optionally, also disable the upper (x86_64) SSE registers to reduce frontend
+// decoder load.
+const unsigned ExegesisX86Target::kUnavailableRegistersSSE[12] = {
+ X86::AH, X86::BH, X86::CH, X86::DH, X86::XMM8, X86::XMM9,
+ X86::XMM10, X86::XMM11, X86::XMM12, X86::XMM13, X86::XMM14, X86::XMM15};
+
// We're using one of R8-R15 because these registers are never hardcoded in
// instructions (e.g. MOVS writes to EDI, ESI, EDX), so they have less
// conflicts.
@@ -864,6 +878,35 @@
return {loadImmediate(Reg, 32, Value)};
if (X86::GR64RegClass.contains(Reg))
return {loadImmediate(Reg, 64, Value)};
+ if (X86::VK8RegClass.contains(Reg) || X86::VK16RegClass.contains(Reg) ||
+ X86::VK32RegClass.contains(Reg) || X86::VK64RegClass.contains(Reg)) {
+ switch (Value.getBitWidth()) {
+ case 8:
+ if (STI.getFeatureBits()[X86::FeatureDQI]) {
+ ConstantInliner CI(Value);
+ return CI.loadAndFinalize(Reg, Value.getBitWidth(), X86::KMOVBkm);
+ }
+ [[fallthrough]];
+ case 16:
+ if (STI.getFeatureBits()[X86::FeatureAVX512]) {
+ ConstantInliner CI(Value.zextOrTrunc(16));
+ return CI.loadAndFinalize(Reg, 16, X86::KMOVWkm);
+ }
+ break;
+ case 32:
+ if (STI.getFeatureBits()[X86::FeatureBWI]) {
+ ConstantInliner CI(Value);
+ return CI.loadAndFinalize(Reg, Value.getBitWidth(), X86::KMOVDkm);
+ }
+ break;
+ case 64:
+ if (STI.getFeatureBits()[X86::FeatureBWI]) {
+ ConstantInliner CI(Value);
+ return CI.loadAndFinalize(Reg, Value.getBitWidth(), X86::KMOVQkm);
+ }
+ break;
+ }
+ }
ConstantInliner CI(Value);
if (X86::VR64RegClass.contains(Reg))
return CI.loadAndFinalize(Reg, 64, X86::MMX_MOVQ64rm);
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 aecae5c..5846242 100644
--- a/src/llvm-project/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/src/llvm-project/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -18,6 +18,7 @@
#include "lib/Error.h"
#include "lib/LlvmState.h"
#include "lib/PerfHelper.h"
+#include "lib/ProgressMeter.h"
#include "lib/SnippetFile.h"
#include "lib/SnippetRepetitor.h"
#include "lib/Target.h"
@@ -35,6 +36,8 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
@@ -44,10 +47,6 @@
namespace llvm {
namespace exegesis {
-static cl::OptionCategory Options("llvm-exegesis options");
-static cl::OptionCategory BenchmarkOptions("llvm-exegesis benchmark options");
-static cl::OptionCategory AnalysisOptions("llvm-exegesis analysis options");
-
static cl::opt<int> OpcodeIndex(
"opcode-index",
cl::desc("opcode to measure, by index, or -1 to measure all opcodes"),
@@ -87,7 +86,8 @@
static cl::opt<exegesis::InstructionBenchmark::ResultAggregationModeE>
ResultAggMode(
"result-aggregation-mode",
- cl::desc("How to aggregate multi-values result"), cl::cat(Options),
+ cl::desc("How to aggregate multi-values result"),
+ cl::cat(BenchmarkOptions),
cl::values(clEnumValN(exegesis::InstructionBenchmark::Min, "min",
"Keep min reading"),
clEnumValN(exegesis::InstructionBenchmark::Max, "max",
@@ -111,6 +111,35 @@
"All of the above and take the minimum of measurements")),
cl::init(exegesis::InstructionBenchmark::Duplicate));
+static cl::opt<bool> BenchmarkMeasurementsPrintProgress(
+ "measurements-print-progress",
+ cl::desc("Produce progress indicator when performing measurements"),
+ cl::cat(BenchmarkOptions), cl::init(false));
+
+static cl::opt<exegesis::BenchmarkPhaseSelectorE> BenchmarkPhaseSelector(
+ "benchmark-phase",
+ cl::desc(
+ "it is possible to stop the benchmarking process after some phase"),
+ cl::cat(BenchmarkOptions),
+ cl::values(
+ clEnumValN(exegesis::BenchmarkPhaseSelectorE::PrepareSnippet,
+ "prepare-snippet",
+ "Only generate the minimal instruction sequence"),
+ clEnumValN(exegesis::BenchmarkPhaseSelectorE::PrepareAndAssembleSnippet,
+ "prepare-and-assemble-snippet",
+ "Same as prepare-snippet, but also dumps an excerpt of the "
+ "sequence (hex encoded)"),
+ clEnumValN(exegesis::BenchmarkPhaseSelectorE::AssembleMeasuredCode,
+ "assemble-measured-code",
+ "Same as prepare-and-assemble-snippet, but also creates the "
+ "full sequence "
+ "that can be dumped to a file using --dump-object-to-disk"),
+ clEnumValN(
+ exegesis::BenchmarkPhaseSelectorE::Measure, "measure",
+ "Same as prepare-measured-code, but also runs the measurement "
+ "(default)")),
+ cl::init(exegesis::BenchmarkPhaseSelectorE::Measure));
+
static cl::opt<unsigned>
NumRepetitions("num-repetitions",
cl::desc("number of time to repeat the asm snippet"),
@@ -134,6 +163,18 @@
cl::desc("ignore instructions that do not define a sched class"),
cl::cat(BenchmarkOptions), cl::init(false));
+static cl::opt<exegesis::InstructionBenchmarkFilter> AnalysisSnippetFilter(
+ "analysis-filter", cl::desc("Filter the benchmarks before analysing them"),
+ cl::cat(BenchmarkOptions),
+ cl::values(
+ clEnumValN(exegesis::InstructionBenchmarkFilter::All, "all",
+ "Keep all benchmarks (default)"),
+ clEnumValN(exegesis::InstructionBenchmarkFilter::RegOnly, "reg-only",
+ "Keep only those benchmarks that do *NOT* involve memory"),
+ clEnumValN(exegesis::InstructionBenchmarkFilter::WithMem, "mem-only",
+ "Keep only the benchmarks that *DO* involve memory")),
+ cl::init(exegesis::InstructionBenchmarkFilter::All));
+
static cl::opt<exegesis::InstructionBenchmarkClustering::ModeE>
AnalysisClusteringAlgorithm(
"analysis-clustering", cl::desc("the clustering algorithm to use"),
@@ -177,16 +218,29 @@
"instead show only such unstable opcodes"),
cl::cat(AnalysisOptions), cl::init(false));
-static cl::opt<std::string> CpuName(
- "mcpu",
- cl::desc("cpu name to use for pfm counters, leave empty to autodetect"),
- cl::cat(Options), cl::init(""));
+static cl::opt<bool> AnalysisOverrideBenchmarksTripleAndCpu(
+ "analysis-override-benchmark-triple-and-cpu",
+ cl::desc("By default, we analyze the benchmarks for the triple/CPU they "
+ "were measured for, but if you want to analyze them for some "
+ "other combination (specified via -mtriple/-mcpu), you can "
+ "pass this flag."),
+ cl::cat(AnalysisOptions), cl::init(false));
-static cl::opt<bool>
- DumpObjectToDisk("dump-object-to-disk",
- cl::desc("dumps the generated benchmark object to disk "
- "and prints a message to access it"),
- cl::cat(BenchmarkOptions), cl::init(true));
+static cl::opt<std::string>
+ TripleName("mtriple",
+ cl::desc("Target triple. See -version for available targets"),
+ cl::cat(Options));
+
+static cl::opt<std::string>
+ MCPU("mcpu",
+ cl::desc("Target a specific cpu type (-mcpu=help for details)"),
+ cl::value_desc("cpu-name"), cl::cat(Options), cl::init("native"));
+
+static cl::opt<bool> DumpObjectToDisk(
+ "dump-object-to-disk",
+ cl::desc("dumps the generated benchmark object to disk "
+ "and prints a message to access it (default = false)"),
+ cl::cat(BenchmarkOptions), cl::init(false));
static ExitOnError ExitOnErr("llvm-exegesis error: ");
@@ -213,7 +267,7 @@
// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
// and returns the opcode indices or {} if snippets should be read from
// `SnippetsFile`.
-static std::vector<unsigned> getOpcodesOrDie(const MCInstrInfo &MCInstrInfo) {
+static std::vector<unsigned> getOpcodesOrDie(const LLVMState &State) {
const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) +
(OpcodeIndex == 0 ? 0 : 1) +
(SnippetsFile.empty() ? 0 : 1);
@@ -228,21 +282,25 @@
return {static_cast<unsigned>(OpcodeIndex)};
if (OpcodeIndex < 0) {
std::vector<unsigned> Result;
- for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
+ unsigned NumOpcodes = State.getInstrInfo().getNumOpcodes();
+ Result.reserve(NumOpcodes);
+ for (unsigned I = 0, E = NumOpcodes; I < E; ++I)
Result.push_back(I);
return Result;
}
// Resolve opcode name -> opcode.
- const auto ResolveName = [&MCInstrInfo](StringRef OpcodeName) -> unsigned {
- for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
- if (MCInstrInfo.getName(I) == OpcodeName)
- return I;
+ const auto ResolveName = [&State](StringRef OpcodeName) -> unsigned {
+ const auto &Map = State.getOpcodeNameToOpcodeIdxMapping();
+ auto I = Map.find(OpcodeName);
+ if (I != Map.end())
+ return I->getSecond();
return 0u;
};
SmallVector<StringRef, 2> Pieces;
StringRef(OpcodeNames.getValue())
.split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
std::vector<unsigned> Result;
+ Result.reserve(Pieces.size());
for (const StringRef &OpcodeName : Pieces) {
if (unsigned Opcode = ResolveName(OpcodeName))
Result.push_back(Opcode);
@@ -290,33 +348,105 @@
return Benchmarks;
}
+static void runBenchmarkConfigurations(
+ const LLVMState &State, ArrayRef<BenchmarkCode> Configurations,
+ ArrayRef<std::unique_ptr<const SnippetRepetitor>> Repetitors,
+ const BenchmarkRunner &Runner) {
+ assert(!Configurations.empty() && "Don't have any configurations to run.");
+ std::optional<raw_fd_ostream> FileOstr;
+ if (BenchmarkFile != "-") {
+ int ResultFD = 0;
+ // Create output file or open existing file and truncate it, once.
+ ExitOnErr(errorCodeToError(openFileForWrite(BenchmarkFile, ResultFD,
+ sys::fs::CD_CreateAlways,
+ sys::fs::OF_TextWithCRLF)));
+ FileOstr.emplace(ResultFD, true /*shouldClose*/);
+ }
+ raw_ostream &Ostr = FileOstr ? *FileOstr : outs();
+
+ std::optional<ProgressMeter<>> Meter;
+ if (BenchmarkMeasurementsPrintProgress)
+ Meter.emplace(Configurations.size());
+ for (const BenchmarkCode &Conf : Configurations) {
+ ProgressMeter<>::ProgressMeterStep MeterStep(Meter ? &*Meter : nullptr);
+ SmallVector<InstructionBenchmark, 2> AllResults;
+
+ for (const std::unique_ptr<const SnippetRepetitor> &Repetitor :
+ Repetitors) {
+ auto RC = ExitOnErr(Runner.getRunnableConfiguration(
+ Conf, NumRepetitions, LoopBodySize, *Repetitor));
+ AllResults.emplace_back(
+ ExitOnErr(Runner.runConfiguration(std::move(RC), DumpObjectToDisk)));
+ }
+ InstructionBenchmark &Result = AllResults.front();
+
+ // If any of our measurements failed, pretend they all have failed.
+ if (AllResults.size() > 1 &&
+ any_of(AllResults, [](const InstructionBenchmark &R) {
+ return R.Measurements.empty();
+ }))
+ Result.Measurements.clear();
+
+ if (RepetitionMode == InstructionBenchmark::RepetitionModeE::AggregateMin) {
+ for (const InstructionBenchmark &OtherResult :
+ ArrayRef<InstructionBenchmark>(AllResults).drop_front()) {
+ llvm::append_range(Result.AssembledSnippet,
+ OtherResult.AssembledSnippet);
+ // Aggregate measurements, but only iff all measurements succeeded.
+ if (Result.Measurements.empty())
+ continue;
+ assert(OtherResult.Measurements.size() == Result.Measurements.size() &&
+ "Expected to have identical number of measurements.");
+ for (auto I : zip(Result.Measurements, OtherResult.Measurements)) {
+ BenchmarkMeasure &Measurement = std::get<0>(I);
+ const BenchmarkMeasure &NewMeasurement = std::get<1>(I);
+ assert(Measurement.Key == NewMeasurement.Key &&
+ "Expected measurements to be symmetric");
+
+ Measurement.PerInstructionValue =
+ std::min(Measurement.PerInstructionValue,
+ NewMeasurement.PerInstructionValue);
+ Measurement.PerSnippetValue = std::min(
+ Measurement.PerSnippetValue, NewMeasurement.PerSnippetValue);
+ }
+ }
+ }
+
+ ExitOnFileError(BenchmarkFile, Result.writeYamlTo(State, Ostr));
+ }
+}
+
void benchmarkMain() {
+ if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure) {
#ifndef HAVE_LIBPFM
- ExitWithError("benchmarking unavailable, LLVM was built without libpfm.");
+ ExitWithError(
+ "benchmarking unavailable, LLVM was built without libpfm. You can pass "
+ "--skip-measurements to skip the actual benchmarking.");
+#else
+ if (exegesis::pfm::pfmInitialize())
+ ExitWithError("cannot initialize libpfm");
#endif
+ }
- if (exegesis::pfm::pfmInitialize())
- ExitWithError("cannot initialize libpfm");
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ InitializeAllExegesisTargets();
- InitializeNativeTarget();
- InitializeNativeTargetAsmPrinter();
- InitializeNativeTargetAsmParser();
- InitializeNativeExegesisTarget();
-
- const LLVMState State(CpuName);
+ const LLVMState State = ExitOnErr(LLVMState::Create(TripleName, MCPU));
// Preliminary check to ensure features needed for requested
// benchmark mode are present on target CPU and/or OS.
- ExitOnErr(State.getExegesisTarget().checkFeatureSupport());
+ if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure)
+ ExitOnErr(State.getExegesisTarget().checkFeatureSupport());
const std::unique_ptr<BenchmarkRunner> Runner =
ExitOnErr(State.getExegesisTarget().createBenchmarkRunner(
- BenchmarkMode, State, ResultAggMode));
+ BenchmarkMode, State, BenchmarkPhaseSelector, ResultAggMode));
if (!Runner) {
ExitWithError("cannot create benchmark runner");
}
- const auto Opcodes = getOpcodesOrDie(State.getInstrInfo());
+ const auto Opcodes = getOpcodesOrDie(State);
SmallVector<std::unique_ptr<const SnippetRepetitor>, 2> Repetitors;
if (RepetitionMode != InstructionBenchmark::RepetitionModeE::AggregateMin)
@@ -370,11 +500,9 @@
if (BenchmarkFile.empty())
BenchmarkFile = "-";
- for (const BenchmarkCode &Conf : Configurations) {
- InstructionBenchmark Result = ExitOnErr(Runner->runConfiguration(
- Conf, NumRepetitions, LoopBodySize, Repetitors, DumpObjectToDisk));
- ExitOnFileError(BenchmarkFile, Result.writeYaml(State, BenchmarkFile));
- }
+ if (!Configurations.empty())
+ runBenchmarkConfigurations(State, Configurations, Repetitors, *Runner);
+
exegesis::pfm::pfmTerminate();
}
@@ -398,6 +526,26 @@
ExitOnFileError(OutputFilename, std::move(Err));
}
+static void filterPoints(MutableArrayRef<InstructionBenchmark> Points,
+ const MCInstrInfo &MCII) {
+ if (AnalysisSnippetFilter == exegesis::InstructionBenchmarkFilter::All)
+ return;
+
+ bool WantPointsWithMemOps =
+ AnalysisSnippetFilter == exegesis::InstructionBenchmarkFilter::WithMem;
+ for (InstructionBenchmark &Point : Points) {
+ if (!Point.Error.empty())
+ continue;
+ if (WantPointsWithMemOps ==
+ any_of(Point.Key.Instructions, [&MCII](const MCInst &Inst) {
+ const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode());
+ return MCDesc.mayLoad() || MCDesc.mayStore();
+ }))
+ continue;
+ Point.Error = "filtered out by user";
+ }
+}
+
static void analysisMain() {
ExitOnErr.setBanner("llvm-exegesis: ");
if (BenchmarkFile.empty())
@@ -410,44 +558,58 @@
"and --analysis-inconsistencies-output-file must be specified");
}
- InitializeNativeTarget();
- InitializeNativeTargetAsmPrinter();
- InitializeNativeTargetDisassembler();
+ InitializeAllAsmPrinters();
+ InitializeAllDisassemblers();
+ InitializeAllExegesisTargets();
+
+ auto MemoryBuffer = ExitOnFileError(
+ BenchmarkFile,
+ errorOrToExpected(MemoryBuffer::getFile(BenchmarkFile, /*IsText=*/true)));
+
+ const auto TriplesAndCpus = ExitOnFileError(
+ BenchmarkFile,
+ InstructionBenchmark::readTriplesAndCpusFromYamls(*MemoryBuffer));
+ if (TriplesAndCpus.empty()) {
+ errs() << "no benchmarks to analyze\n";
+ return;
+ }
+ if (TriplesAndCpus.size() > 1) {
+ ExitWithError("analysis file contains benchmarks from several CPUs. This "
+ "is unsupported.");
+ }
+ auto TripleAndCpu = *TriplesAndCpus.begin();
+ if (AnalysisOverrideBenchmarksTripleAndCpu) {
+ llvm::errs() << "overridding file CPU name (" << TripleAndCpu.CpuName
+ << ") with provided tripled (" << TripleName
+ << ") and CPU name (" << MCPU << ")\n";
+ TripleAndCpu.LLVMTriple = TripleName;
+ TripleAndCpu.CpuName = MCPU;
+ }
+ llvm::errs() << "using Triple '" << TripleAndCpu.LLVMTriple << "' and CPU '"
+ << TripleAndCpu.CpuName << "'\n";
// Read benchmarks.
- const LLVMState State("");
- const std::vector<InstructionBenchmark> Points = ExitOnFileError(
- BenchmarkFile, InstructionBenchmark::readYamls(State, BenchmarkFile));
+ const LLVMState State = ExitOnErr(
+ LLVMState::Create(TripleAndCpu.LLVMTriple, TripleAndCpu.CpuName));
+ std::vector<InstructionBenchmark> Points = ExitOnFileError(
+ BenchmarkFile, InstructionBenchmark::readYamls(State, *MemoryBuffer));
outs() << "Parsed " << Points.size() << " benchmark points\n";
if (Points.empty()) {
errs() << "no benchmarks to analyze\n";
return;
}
- // FIXME: Check that all points have the same triple/cpu.
// FIXME: Merge points from several runs (latency and uops).
- std::string Error;
- const auto *TheTarget =
- TargetRegistry::lookupTarget(Points[0].LLVMTriple, Error);
- if (!TheTarget) {
- errs() << "unknown target '" << Points[0].LLVMTriple << "'\n";
- return;
- }
-
- std::unique_ptr<MCSubtargetInfo> SubtargetInfo(
- TheTarget->createMCSubtargetInfo(Points[0].LLVMTriple, CpuName, ""));
-
- std::unique_ptr<MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
- assert(InstrInfo && "Unable to create instruction info!");
+ filterPoints(Points, State.getInstrInfo());
const auto Clustering = ExitOnErr(InstructionBenchmarkClustering::create(
Points, AnalysisClusteringAlgorithm, AnalysisDbscanNumPoints,
- AnalysisClusteringEpsilon, SubtargetInfo.get(), InstrInfo.get()));
+ AnalysisClusteringEpsilon, &State.getSubtargetInfo(),
+ &State.getInstrInfo()));
- const Analysis Analyzer(
- *TheTarget, std::move(SubtargetInfo), std::move(InstrInfo), Clustering,
- AnalysisInconsistencyEpsilon, AnalysisDisplayUnstableOpcodes, CpuName);
+ const Analysis Analyzer(State, Clustering, AnalysisInconsistencyEpsilon,
+ AnalysisDisplayUnstableOpcodes);
maybeRunAnalysis<Analysis::PrintClusters>(Analyzer, "analysis clusters",
AnalysisClustersOutputFile);
@@ -461,7 +623,27 @@
int main(int Argc, char **Argv) {
using namespace llvm;
- cl::ParseCommandLineOptions(Argc, Argv, "");
+
+ InitLLVM X(Argc, Argv);
+
+ // Initialize targets so we can print them when flag --version is specified.
+ InitializeAllTargetInfos();
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+
+ // Register the Target and CPU printer for --version.
+ cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);
+
+ // Enable printing of available targets when flag --version is specified.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ cl::HideUnrelatedOptions({&llvm::exegesis::Options,
+ &llvm::exegesis::BenchmarkOptions,
+ &llvm::exegesis::AnalysisOptions});
+
+ cl::ParseCommandLineOptions(Argc, Argv,
+ "llvm host machine instruction characteristics "
+ "measurment and analysis.\n");
exegesis::ExitOnErr.setExitCodeMapper([](const Error &Err) {
if (Err.isA<exegesis::ClusteringError>())
diff --git a/src/llvm-project/llvm/tools/llvm-extract/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-extract/CMakeLists.txt
index ce2a78d..4521b5e 100644
--- a/src/llvm-project/llvm/tools/llvm-extract/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-extract/CMakeLists.txt
@@ -1,8 +1,11 @@
set(LLVM_LINK_COMPONENTS
+ Analysis
BitWriter
Core
IPO
IRReader
+ IRPrinter
+ Passes
Support
)
diff --git a/src/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp b/src/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp
index ffd2a39..a879c20 100644
--- a/src/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp
+++ b/src/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp
@@ -18,10 +18,10 @@
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRPrinter/IRPrintingPasses.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/Pass.h"
+#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
@@ -31,8 +31,14 @@
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/BlockExtractor.h"
+#include "llvm/Transforms/IPO/ExtractGV.h"
+#include "llvm/Transforms/IPO/GlobalDCE.h"
+#include "llvm/Transforms/IPO/StripDeadPrototypes.h"
+#include "llvm/Transforms/IPO/StripSymbols.h"
#include <memory>
#include <utility>
+
using namespace llvm;
cl::OptionCategory ExtractCat("llvm-extract Options");
@@ -317,9 +323,22 @@
{
std::vector<GlobalValue *> Gvs(GVs.begin(), GVs.end());
- legacy::PassManager Extract;
- Extract.add(createGVExtractionPass(Gvs, DeleteFn, KeepConstInit));
- Extract.run(*M);
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ PassBuilder PB;
+
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ ModulePassManager PM;
+ PM.addPass(ExtractGVPass(Gvs, DeleteFn, KeepConstInit));
+ PM.run(*M, MAM);
// Now that we have all the GVs we want, mark the module as fully
// materialized.
@@ -331,9 +350,9 @@
// functions.
if (!ExtractBlocks.empty()) {
// Figure out which BasicBlocks we should extract.
- SmallVector<SmallVector<BasicBlock *, 16>, 4> GroupOfBBs;
+ std::vector<std::vector<BasicBlock *>> GroupOfBBs;
for (auto &P : BBMap) {
- SmallVector<BasicBlock *, 16> BBs;
+ std::vector<BasicBlock *> BBs;
for (StringRef BBName : P.second) {
// The function has been materialized, so add its matching basic blocks
// to the block extractor list, or fail if a name is not found.
@@ -351,19 +370,45 @@
GroupOfBBs.push_back(BBs);
}
- legacy::PassManager PM;
- PM.add(createBlockExtractorPass(GroupOfBBs, true));
- PM.run(*M);
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ PassBuilder PB;
+
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ ModulePassManager PM;
+ PM.addPass(BlockExtractorPass(std::move(GroupOfBBs), true));
+ PM.run(*M, MAM);
}
// In addition to deleting all other functions, we also want to spiff it
// up a little bit. Do this now.
- legacy::PassManager Passes;
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ PassBuilder PB;
+
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ ModulePassManager PM;
if (!DeleteFn)
- Passes.add(createGlobalDCEPass()); // Delete unreachable globals
- Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info
- Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls
+ PM.addPass(GlobalDCEPass());
+ PM.addPass(StripDeadDebugInfoPass());
+ PM.addPass(StripDeadPrototypesPass());
std::error_code EC;
ToolOutputFile Out(OutputFilename, EC, sys::fs::OF_None);
@@ -373,12 +418,11 @@
}
if (OutputAssembly)
- Passes.add(
- createPrintModulePass(Out.os(), "", PreserveAssemblyUseListOrder));
+ PM.addPass(PrintModulePass(Out.os(), "", PreserveAssemblyUseListOrder));
else if (Force || !CheckBitcodeOutputToConsole(Out.os()))
- Passes.add(createBitcodeWriterPass(Out.os(), PreserveBitcodeUseListOrder));
+ PM.addPass(BitcodeWriterPass(Out.os(), PreserveBitcodeUseListOrder));
- Passes.run(*M.get());
+ PM.run(*M, MAM);
// Declare success.
Out.keep();
diff --git a/src/llvm-project/llvm/tools/llvm-go/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-go/CMakeLists.txt
deleted file mode 100644
index 20393f7..0000000
--- a/src/llvm-project/llvm/tools/llvm-go/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-if(LLVM_BINDINGS MATCHES "go")
- set(binpath ${CMAKE_BINARY_DIR}/bin/llvm-go${CMAKE_EXECUTABLE_SUFFIX})
- add_custom_command(OUTPUT ${binpath}
- COMMAND ${GO_EXECUTABLE} build -o ${binpath} llvm-go.go
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/llvm-go.go
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMENT "Building Go executable llvm-go")
- add_custom_target(llvm-go ALL DEPENDS ${binpath})
-endif()
diff --git a/src/llvm-project/llvm/tools/llvm-go/llvm-go.go b/src/llvm-project/llvm/tools/llvm-go/llvm-go.go
deleted file mode 100644
index dc928b8..0000000
--- a/src/llvm-project/llvm/tools/llvm-go/llvm-go.go
+++ /dev/null
@@ -1,315 +0,0 @@
-//===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
-//
-// 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 tool lets us build LLVM components within the tree by setting up a
-// $GOPATH that resembles a tree fetched in the normal way with "go get".
-//
-//===----------------------------------------------------------------------===//
-
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
-)
-
-const (
- linkmodeComponentLibs = "component-libs"
- linkmodeDylib = "dylib"
-)
-
-type pkg struct {
- llvmpath, pkgpath string
-}
-
-var packages = []pkg{
- {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
-}
-
-type compilerFlags struct {
- cpp, cxx, ld string
-}
-
-var components = []string{
- "all-targets",
- "analysis",
- "asmparser",
- "asmprinter",
- "bitreader",
- "bitwriter",
- "codegen",
- "core",
- "coroutines",
- "debuginfodwarf",
- "executionengine",
- "instrumentation",
- "interpreter",
- "ipo",
- "irreader",
- "linker",
- "mc",
- "mcjit",
- "objcarcopts",
- "option",
- "profiledata",
- "scalaropts",
- "support",
- "target",
-}
-
-func llvmConfig(args ...string) string {
- configpath := os.Getenv("LLVM_CONFIG")
- if configpath == "" {
- bin, _ := filepath.Split(os.Args[0])
- configpath = filepath.Join(bin, "llvm-config")
- }
-
- cmd := exec.Command(configpath, args...)
- cmd.Stderr = os.Stderr
- out, err := cmd.Output()
- if err != nil {
- panic(err.Error())
- }
-
- outstr := string(out)
- outstr = strings.TrimSuffix(outstr, "\n")
- outstr = strings.Replace(outstr, "\n", " ", -1)
- return outstr
-}
-
-func llvmFlags() compilerFlags {
- args := append([]string{"--ldflags", "--libs", "--system-libs"}, components...)
- ldflags := llvmConfig(args...)
- stdLibOption := ""
- if strings.Contains(llvmConfig("--cxxflags"), "-stdlib=libc++") {
- // If libc++ is used to build LLVM libraries, -stdlib=libc++ is
- // needed to resolve dependent symbols
- stdLibOption = "-stdlib=libc++"
- }
- if runtime.GOOS == "aix" {
- // AIX linker does not honour `-rpath`, the closest substitution
- // is `-blibpath`
- ldflags = "-Wl,-blibpath:" + llvmConfig("--libdir") + " " + ldflags
- } else if runtime.GOOS != "darwin" {
- // OS X doesn't like -rpath with cgo. See:
- // https://github.com/golang/go/issues/7293
- ldflags = "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
- }
- return compilerFlags{
- cpp: llvmConfig("--cppflags"),
- cxx: "-std=c++14" + " " + stdLibOption,
- ld: ldflags,
- }
-}
-
-func addTag(args []string, tag string) []string {
- args = append([]string{}, args...)
- addedTag := false
- for i, a := range args {
- if strings.HasPrefix(a, "-tags=") {
- args[i] = a + " " + tag
- addedTag = true
- } else if a == "-tags" && i+1 < len(args) {
- args[i+1] = args[i+1] + " " + tag
- addedTag = true
- }
- }
- if !addedTag {
- args = append([]string{args[0], "-tags", tag}, args[1:]...)
- }
- return args
-}
-
-func printComponents() {
- fmt.Println(strings.Join(components, " "))
-}
-
-func printConfig() {
- flags := llvmFlags()
-
- fmt.Printf(`// +build !byollvm
-
-// This file is generated by llvm-go, do not edit.
-
-package llvm
-
-/*
-#cgo CPPFLAGS: %s
-#cgo CXXFLAGS: %s
-#cgo LDFLAGS: %s
-*/
-import "C"
-
-type (run_build_sh int)
-`, flags.cpp, flags.cxx, flags.ld)
-}
-
-func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string, packages []pkg) {
- args = addTag(args, "byollvm")
-
- srcdir := llvmConfig("--src-root")
-
- tmpgopath, err := ioutil.TempDir("", "gopath")
- if err != nil {
- panic(err.Error())
- }
-
- for _, p := range packages {
- path := filepath.Join(tmpgopath, "src", p.pkgpath)
- err := os.MkdirAll(filepath.Dir(path), os.ModePerm)
- if err != nil {
- panic(err.Error())
- }
-
- abspath := p.llvmpath
- if !filepath.IsAbs(abspath) {
- abspath = filepath.Join(srcdir, abspath)
- }
-
- err = os.Symlink(abspath, path)
- if err != nil {
- panic(err.Error())
- }
- }
-
- newpath := os.Getenv("PATH")
-
- newgopathlist := []string{tmpgopath}
- newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...)
- newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator))
-
- flags := llvmFlags()
-
- newenv := []string{
- "CC=" + cc,
- "CXX=" + cxx,
- "CGO_CPPFLAGS=" + flags.cpp + " " + cppflags,
- "CGO_CXXFLAGS=" + flags.cxx + " " + cxxflags,
- "CGO_LDFLAGS=" + flags.ld + " " + ldflags,
- "GOPATH=" + newgopath,
- "PATH=" + newpath,
- }
- if llgo != "" {
- newenv = append(newenv, "GCCGO="+llgo)
- }
-
- for _, v := range os.Environ() {
- if !strings.HasPrefix(v, "CC=") &&
- !strings.HasPrefix(v, "CXX=") &&
- !strings.HasPrefix(v, "CGO_CPPFLAGS=") &&
- !strings.HasPrefix(v, "CGO_CXXFLAGS=") &&
- !strings.HasPrefix(v, "CGO_LDFLAGS=") &&
- !strings.HasPrefix(v, "GCCGO=") &&
- !strings.HasPrefix(v, "GOPATH=") &&
- !strings.HasPrefix(v, "PATH=") {
- newenv = append(newenv, v)
- }
- }
-
- gocmdpath, err := exec.LookPath(gocmd)
- if err != nil {
- panic(err.Error())
- }
-
- proc, err := os.StartProcess(gocmdpath, append([]string{gocmd}, args...),
- &os.ProcAttr{
- Env: newenv,
- Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
- })
- if err != nil {
- panic(err.Error())
- }
- ps, err := proc.Wait()
- if err != nil {
- panic(err.Error())
- }
-
- os.RemoveAll(tmpgopath)
-
- if !ps.Success() {
- os.Exit(1)
- }
-}
-
-func usage() {
- fmt.Println(`Usage: llvm-go subcommand [flags]
-
-Available subcommands: build get install run test print-components print-config`)
- os.Exit(0)
-}
-
-func main() {
- cc := os.Getenv("CC")
- cxx := os.Getenv("CXX")
- cppflags := os.Getenv("CGO_CPPFLAGS")
- cxxflags := os.Getenv("CGO_CXXFLAGS")
- ldflags := os.Getenv("CGO_LDFLAGS")
- gocmd := "go"
- llgo := ""
- packagesString := ""
-
- flags := []struct {
- name string
- dest *string
- }{
- {"cc", &cc},
- {"cxx", &cxx},
- {"go", &gocmd},
- {"llgo", &llgo},
- {"cppflags", &cppflags},
- {"ldflags", &ldflags},
- {"packages", &packagesString},
- }
-
- args := os.Args[1:]
-LOOP:
- for {
- if len(args) == 0 {
- usage()
- }
- for _, flag := range flags {
- if strings.HasPrefix(args[0], flag.name+"=") {
- *flag.dest = args[0][len(flag.name)+1:]
- args = args[1:]
- continue LOOP
- }
- }
- break
- }
-
- packages := packages
- if packagesString != "" {
- for _, field := range strings.Fields(packagesString) {
- pos := strings.IndexRune(field, '=')
- if pos == -1 {
- fmt.Fprintf(os.Stderr, "invalid packages value %q, expected 'pkgpath=llvmpath [pkgpath=llvmpath ...]'\n", packagesString)
- os.Exit(1)
- }
- packages = append(packages, pkg{
- pkgpath: field[:pos],
- llvmpath: field[pos+1:],
- })
- }
- }
-
- switch args[0] {
- case "build", "get", "install", "run", "test":
- runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, packages)
- case "print-components":
- printComponents()
- case "print-config":
- printConfig()
- default:
- usage()
- }
-}
diff --git a/src/llvm-project/llvm/tools/llvm-gsymutil/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-gsymutil/CMakeLists.txt
index bda3c8d..5624005 100644
--- a/src/llvm-project/llvm/tools/llvm-gsymutil/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-gsymutil/CMakeLists.txt
@@ -6,6 +6,7 @@
Object
Support
Target
+ TargetParser
)
add_llvm_tool(llvm-gsymutil
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 4eaab07..943c056 100644
--- a/src/llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -41,6 +41,7 @@
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
#include "llvm/DebugInfo/GSYM/LookupResult.h"
#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
+#include <optional>
using namespace llvm;
using namespace gsym;
@@ -186,17 +187,17 @@
///
/// \returns A valid image base address if we are able to extract one.
template <class ELFT>
-static llvm::Optional<uint64_t>
+static std::optional<uint64_t>
getImageBaseAddress(const object::ELFFile<ELFT> &ELFFile) {
auto PhdrRangeOrErr = ELFFile.program_headers();
if (!PhdrRangeOrErr) {
consumeError(PhdrRangeOrErr.takeError());
- return llvm::None;
+ return std::nullopt;
}
for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
if (Phdr.p_type == ELF::PT_LOAD)
return (uint64_t)Phdr.p_vaddr;
- return llvm::None;
+ return std::nullopt;
}
/// Determine the virtual address that is considered the base address of mach-o
@@ -207,7 +208,7 @@
/// \param MachO A mach-o object file we will search.
///
/// \returns A valid image base address if we are able to extract one.
-static llvm::Optional<uint64_t>
+static std::optional<uint64_t>
getImageBaseAddress(const object::MachOObjectFile *MachO) {
for (const auto &Command : MachO->load_commands()) {
if (Command.C.cmd == MachO::LC_SEGMENT) {
@@ -222,7 +223,7 @@
return SLC.vmaddr;
}
}
- return llvm::None;
+ return std::nullopt;
}
/// Determine the virtual address that is considered the base address of an
@@ -237,7 +238,7 @@
/// \param Obj An object file we will search.
///
/// \returns A valid image base address if we are able to extract one.
-static llvm::Optional<uint64_t> getImageBaseAddress(object::ObjectFile &Obj) {
+static std::optional<uint64_t> getImageBaseAddress(object::ObjectFile &Obj) {
if (const auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj))
return getImageBaseAddress(MachO);
else if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(&Obj))
@@ -248,7 +249,7 @@
return getImageBaseAddress(ELFObj->getELFFile());
else if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(&Obj))
return getImageBaseAddress(ELFObj->getELFFile());
- return llvm::None;
+ return std::nullopt;
}
static llvm::Error handleObjectFile(ObjectFile &Obj,
@@ -285,7 +286,6 @@
if (!DICtx)
return createStringError(std::errc::invalid_argument,
"unable to create DWARF context");
- logAllUnhandledErrors(DICtx->loadRegisterInfo(Obj), OS, "DwarfTransformer: ");
// Make a DWARF transformer object and populate the ranges of the code
// so we don't end up adding invalid functions to GSYM data.
@@ -480,7 +480,7 @@
std::string InputLine;
std::string CurrentGSYMPath;
- llvm::Optional<Expected<GsymReader>> CurrentGsym;
+ std::optional<Expected<GsymReader>> CurrentGsym;
while (std::getline(std::cin, InputLine)) {
// Strip newline characters.
@@ -496,6 +496,7 @@
CurrentGsym = GsymReader::openFile(GSYMPath);
if (!*CurrentGsym)
error(GSYMPath, CurrentGsym->takeError());
+ CurrentGSYMPath = GSYMPath;
}
uint64_t Addr;
diff --git a/src/llvm-project/llvm/tools/llvm-ifs/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-ifs/CMakeLists.txt
index 483610d..23bc1ec 100644
--- a/src/llvm-project/llvm/tools/llvm-ifs/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-ifs/CMakeLists.txt
@@ -1,8 +1,9 @@
set(LLVM_LINK_COMPONENTS
BinaryFormat
- InterfaceStub
+ InterfaceStub
Object
Support
+ TargetParser
TextAPI
ObjectYAML
Option
@@ -18,4 +19,6 @@
DEPENDS
IFSOptsTableGen
+
+ GENERATE_DRIVER
)
diff --git a/src/llvm-project/llvm/tools/llvm-ifs/ErrorCollector.h b/src/llvm-project/llvm/tools/llvm-ifs/ErrorCollector.h
index d3a814b..2b91e90 100644
--- a/src/llvm-project/llvm/tools/llvm-ifs/ErrorCollector.h
+++ b/src/llvm-project/llvm/tools/llvm-ifs/ErrorCollector.h
@@ -21,13 +21,12 @@
#ifndef LLVM_TOOLS_LLVM_IFS_ERRORCOLLECTOR_H
#define LLVM_TOOLS_LLVM_IFS_ERRORCOLLECTOR_H
+#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
namespace llvm {
-class Error;
-
namespace ifs {
class ErrorCollector {
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 6082290..0ca9dfd 100644
--- a/src/llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ifs/llvm-ifs.cpp
@@ -32,6 +32,7 @@
#include "llvm/TextAPI/InterfaceFile.h"
#include "llvm/TextAPI/TextAPIReader.h"
#include "llvm/TextAPI/TextAPIWriter.h"
+#include <optional>
#include <set>
#include <string>
#include <vector>
@@ -59,11 +60,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -75,22 +79,24 @@
#undef OPTION
};
-class IFSOptTable : public opt::OptTable {
+class IFSOptTable : public opt::GenericOptTable {
public:
- IFSOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+ IFSOptTable() : opt::GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
};
struct DriverConfig {
std::vector<std::string> InputFilePaths;
- Optional<FileFormat> InputFormat;
- Optional<FileFormat> OutputFormat;
+ std::optional<FileFormat> InputFormat;
+ std::optional<FileFormat> OutputFormat;
- Optional<std::string> HintIfsTarget;
- Optional<std::string> OptTargetTriple;
- Optional<IFSArch> OverrideArch;
- Optional<IFSBitWidthType> OverrideBitWidth;
- Optional<IFSEndiannessType> OverrideEndianness;
+ std::optional<std::string> HintIfsTarget;
+ std::optional<std::string> OptTargetTriple;
+ std::optional<IFSArch> OverrideArch;
+ std::optional<IFSBitWidthType> OverrideBitWidth;
+ std::optional<IFSEndiannessType> OverrideEndianness;
bool StripIfsArch = false;
bool StripIfsBitwidth = false;
@@ -102,12 +108,12 @@
std::vector<std::string> Exclude;
- Optional<std::string> SoName;
+ std::optional<std::string> SoName;
- Optional<std::string> Output;
- Optional<std::string> OutputElf;
- Optional<std::string> OutputIfs;
- Optional<std::string> OutputTbd;
+ std::optional<std::string> Output;
+ std::optional<std::string> OutputElf;
+ std::optional<std::string> OutputIfs;
+ std::optional<std::string> OutputTbd;
bool WriteIfChanged = false;
};
@@ -129,7 +135,7 @@
}
static Expected<std::unique_ptr<IFSStub>>
-readInputFile(Optional<FileFormat> &InputFormat, StringRef FilePath) {
+readInputFile(std::optional<FileFormat> &InputFormat, StringRef FilePath) {
// Read in file.
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
MemoryBuffer::getFileOrSTDIN(FilePath, /*IsText=*/true);
@@ -305,10 +311,10 @@
for (const opt::Arg *A : Args.filtered(OPT_INPUT))
Config.InputFilePaths.push_back(A->getValue());
if (const opt::Arg *A = Args.getLastArg(OPT_input_format_EQ)) {
- Config.InputFormat = StringSwitch<Optional<FileFormat>>(A->getValue())
+ Config.InputFormat = StringSwitch<std::optional<FileFormat>>(A->getValue())
.Case("IFS", FileFormat::IFS)
.Case("ELF", FileFormat::ELF)
- .Default(None);
+ .Default(std::nullopt);
if (!Config.InputFormat)
fatalError(Twine("invalid argument '") + A->getValue());
}
@@ -318,11 +324,11 @@
" option: Cannot find option named '" + OptionName + "'!");
};
if (const opt::Arg *A = Args.getLastArg(OPT_output_format_EQ)) {
- Config.OutputFormat = StringSwitch<Optional<FileFormat>>(A->getValue())
+ Config.OutputFormat = StringSwitch<std::optional<FileFormat>>(A->getValue())
.Case("IFS", FileFormat::IFS)
.Case("ELF", FileFormat::ELF)
.Case("TBD", FileFormat::TBD)
- .Default(None);
+ .Default(std::nullopt);
if (!Config.OutputFormat)
OptionNotFound("--output-format", A->getValue());
}
@@ -340,10 +346,10 @@
}
if (const opt::Arg *A = Args.getLastArg(OPT_endianness_EQ)) {
Config.OverrideEndianness =
- StringSwitch<Optional<IFSEndiannessType>>(A->getValue())
+ StringSwitch<std::optional<IFSEndiannessType>>(A->getValue())
.Case("little", IFSEndiannessType::Little)
.Case("big", IFSEndiannessType::Big)
- .Default(None);
+ .Default(std::nullopt);
if (!Config.OverrideEndianness)
OptionNotFound("--endianness", A->getValue());
}
@@ -376,7 +382,7 @@
return Config;
}
-int main(int argc, char *argv[]) {
+int llvm_ifs_main(int argc, char **argv) {
DriverConfig Config = parseArgs(argc, argv);
if (Config.InputFilePaths.empty())
@@ -533,33 +539,32 @@
<< "Triple should be defined when output format is TBD";
return -1;
}
- return writeTbdStub(llvm::Triple(Stub.Target.Triple.value()),
- Stub.Symbols, "TBD", Out);
+ return writeTbdStub(llvm::Triple(*Stub.Target.Triple), Stub.Symbols,
+ "TBD", Out);
}
case FileFormat::IFS: {
Stub.IfsVersion = IfsVersionCurrent;
- if (Config.InputFormat.value() == FileFormat::ELF &&
- Config.HintIfsTarget) {
+ if (*Config.InputFormat == FileFormat::ELF && Config.HintIfsTarget) {
std::error_code HintEC(1, std::generic_category());
IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget);
- if (Stub.Target.Arch.value() != HintTarget.Arch.value())
+ if (*Stub.Target.Arch != *HintTarget.Arch)
fatalError(make_error<StringError>(
"Triple hint does not match the actual architecture", HintEC));
- if (Stub.Target.Endianness.value() != HintTarget.Endianness.value())
+ if (*Stub.Target.Endianness != *HintTarget.Endianness)
fatalError(make_error<StringError>(
"Triple hint does not match the actual endianness", HintEC));
- if (Stub.Target.BitWidth.value() != HintTarget.BitWidth.value())
+ if (*Stub.Target.BitWidth != *HintTarget.BitWidth)
fatalError(make_error<StringError>(
"Triple hint does not match the actual bit width", HintEC));
stripIFSTarget(Stub, true, false, false, false);
- Stub.Target.Triple = Config.HintIfsTarget.value();
+ Stub.Target.Triple = *Config.HintIfsTarget;
} else {
stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch,
Config.StripIfsEndianness, Config.StripIfsBitwidth);
}
Error IFSWriteError =
- writeIFS(Config.Output.value(), Stub, Config.WriteIfChanged);
+ writeIFS(*Config.Output, Stub, Config.WriteIfChanged);
if (IFSWriteError)
fatalError(std::move(IFSWriteError));
break;
@@ -588,28 +593,27 @@
}
if (Config.OutputIfs) {
Stub.IfsVersion = IfsVersionCurrent;
- if (Config.InputFormat.value() == FileFormat::ELF &&
- Config.HintIfsTarget) {
+ if (*Config.InputFormat == FileFormat::ELF && Config.HintIfsTarget) {
std::error_code HintEC(1, std::generic_category());
IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget);
- if (Stub.Target.Arch.value() != HintTarget.Arch.value())
+ if (*Stub.Target.Arch != *HintTarget.Arch)
fatalError(make_error<StringError>(
"Triple hint does not match the actual architecture", HintEC));
- if (Stub.Target.Endianness.value() != HintTarget.Endianness.value())
+ if (*Stub.Target.Endianness != *HintTarget.Endianness)
fatalError(make_error<StringError>(
"Triple hint does not match the actual endianness", HintEC));
- if (Stub.Target.BitWidth.value() != HintTarget.BitWidth.value())
+ if (*Stub.Target.BitWidth != *HintTarget.BitWidth)
fatalError(make_error<StringError>(
"Triple hint does not match the actual bit width", HintEC));
stripIFSTarget(Stub, true, false, false, false);
- Stub.Target.Triple = Config.HintIfsTarget.value();
+ Stub.Target.Triple = *Config.HintIfsTarget;
} else {
stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch,
Config.StripIfsEndianness, Config.StripIfsBitwidth);
}
Error IFSWriteError =
- writeIFS(Config.OutputIfs.value(), Stub, Config.WriteIfChanged);
+ writeIFS(*Config.OutputIfs, Stub, Config.WriteIfChanged);
if (IFSWriteError)
fatalError(std::move(IFSWriteError));
}
@@ -626,8 +630,8 @@
<< "Triple should be defined when output format is TBD";
return -1;
}
- return writeTbdStub(llvm::Triple(Stub.Target.Triple.value()),
- Stub.Symbols, "TBD", Out);
+ return writeTbdStub(llvm::Triple(*Stub.Target.Triple), Stub.Symbols,
+ "TBD", Out);
}
}
return 0;
diff --git a/src/llvm-project/llvm/tools/llvm-isel-fuzzer/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-isel-fuzzer/CMakeLists.txt
index 32b6538..f30407a 100644
--- a/src/llvm-project/llvm/tools/llvm-isel-fuzzer/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-isel-fuzzer/CMakeLists.txt
@@ -17,6 +17,7 @@
SelectionDAG
Support
Target
+ TargetParser
)
add_llvm_fuzzer(llvm-isel-fuzzer
llvm-isel-fuzzer.cpp
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 599c414..dbcdba7 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
@@ -42,7 +42,7 @@
OptLevel("O",
cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
"(default = '-O2')"),
- cl::Prefix, cl::init(' '));
+ cl::Prefix, cl::init('2'));
static cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
@@ -144,16 +144,12 @@
std::string CPUStr = codegen::getCPUStr(),
FeaturesStr = codegen::getFeaturesStr();
- CodeGenOpt::Level OLvl = CodeGenOpt::Default;
- switch (OptLevel) {
- default:
+ CodeGenOpt::Level OLvl;
+ if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
+ OLvl = *Level;
+ } else {
errs() << argv[0] << ": invalid optimization level.\n";
return 1;
- case ' ': break;
- case '0': OLvl = CodeGenOpt::None; break;
- case '1': OLvl = CodeGenOpt::Less; break;
- case '2': OLvl = CodeGenOpt::Default; break;
- case '3': OLvl = CodeGenOpt::Aggressive; break;
}
TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple);
diff --git a/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt
index 65cc0c9..b7371e7 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/CMakeLists.txt
@@ -16,6 +16,7 @@
OrcTargetProcess
RuntimeDyld
Support
+ TargetParser
)
add_llvm_tool(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 2e7b000..415aee7 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
@@ -25,8 +25,8 @@
static bool isCOFFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
- auto EItr = std::find_if(B.edges().begin(), B.edges().end(),
- [](Edge &E) { return E.isRelocation(); });
+ auto EItr =
+ llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
if (EItr == B.edges().end())
return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
B.getSection().getName() +
@@ -80,13 +80,12 @@
for (auto &Sec : G.sections()) {
LLVM_DEBUG({
dbgs() << " Section \"" << Sec.getName() << "\": "
- << (llvm::empty(Sec.symbols()) ? "empty. skipping."
- : "processing...")
+ << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
<< "\n";
});
// Skip empty sections.
- if (llvm::empty(Sec.symbols()))
+ if (Sec.symbols().empty())
continue;
if (FileInfo.SectionInfos.count(Sec.getName()))
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 d79dbc4..2b798f9 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
@@ -25,8 +25,8 @@
static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
- auto EItr = std::find_if(B.edges().begin(), B.edges().end(),
- [](Edge &E) { return E.isRelocation(); });
+ auto EItr =
+ llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
if (EItr == B.edges().end())
return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
B.getSection().getName() +
@@ -82,13 +82,12 @@
for (auto &Sec : G.sections()) {
LLVM_DEBUG({
dbgs() << " Section \"" << Sec.getName() << "\": "
- << (llvm::empty(Sec.symbols()) ? "empty. skipping."
- : "processing...")
+ << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
<< "\n";
});
// Skip empty sections.
- if (llvm::empty(Sec.symbols()))
+ if (Sec.symbols().empty())
continue;
if (FileInfo.SectionInfos.count(Sec.getName()))
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 34246ca..71c83f2 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
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
@@ -164,6 +165,9 @@
SimpleRemoteEPCServer::defaultBootstrapSymbols();
S.services().push_back(
std::make_unique<rt_bootstrap::SimpleExecutorMemoryManager>());
+ S.services().push_back(
+ std::make_unique<
+ rt_bootstrap::ExecutorSharedMemoryMapperService>());
return Error::success();
},
InFD, OutFD));
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 ed7fd1a..bcb2f25 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
@@ -27,8 +27,8 @@
}
static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
- auto EItr = std::find_if(B.edges().begin(), B.edges().end(),
- [](Edge &E) { return E.isRelocation(); });
+ auto EItr =
+ llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
if (EItr == B.edges().end())
return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
B.getSection().getName() +
@@ -84,13 +84,12 @@
for (auto &Sec : G.sections()) {
LLVM_DEBUG({
dbgs() << " Section \"" << Sec.getName() << "\": "
- << (llvm::empty(Sec.symbols()) ? "empty. skipping."
- : "processing...")
+ << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
<< "\n";
});
// Skip empty sections.
- if (llvm::empty(Sec.symbols()))
+ if (Sec.symbols().empty())
continue;
if (FileInfo.SectionInfos.count(Sec.getName()))
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 c0d36b3..4180be4 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -15,6 +15,8 @@
#include "llvm-jitlink.h"
#include "llvm/BinaryFormat/Magic.h"
+#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/ELFNixPlatform.h"
@@ -24,7 +26,9 @@
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
+#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
#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/RegisterEHFrames.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -50,6 +54,7 @@
#include "llvm/Support/Timer.h"
#include <cstring>
+#include <deque>
#include <list>
#include <string>
@@ -93,6 +98,11 @@
cl::desc("Link against library X with hidden visibility"),
cl::cat(JITLinkCategory));
+static cl::opt<bool> SearchSystemLibrary(
+ "search-sys-lib",
+ cl::desc("Add system library paths to library search paths"),
+ cl::init(false), cl::cat(JITLinkCategory));
+
static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
cl::init(false), cl::cat(JITLinkCategory));
@@ -228,6 +238,11 @@
cl::desc("Show FailedToMaterialize errors"),
cl::init(false), cl::cat(JITLinkCategory));
+static cl::opt<bool> UseSharedMemory(
+ "use-shared-memory",
+ cl::desc("Use shared memory to transfer generated code and data"),
+ cl::init(false), cl::cat(JITLinkCategory));
+
static ExitOnError ExitOnErr;
static LLVM_ATTRIBUTE_USED void linkComponents() {
@@ -388,11 +403,11 @@
Sections.push_back(&S);
llvm::sort(Sections, [](const Section *LHS, const Section *RHS) {
- if (llvm::empty(LHS->symbols()) && llvm::empty(RHS->symbols()))
+ if (LHS->symbols().empty() && RHS->symbols().empty())
return false;
- if (llvm::empty(LHS->symbols()))
+ if (LHS->symbols().empty())
return false;
- if (llvm::empty(RHS->symbols()))
+ if (RHS->symbols().empty())
return true;
SectionRange LHSRange(*LHS);
SectionRange RHSRange(*RHS);
@@ -401,7 +416,7 @@
for (auto *S : Sections) {
OS << S->getName() << " content:";
- if (llvm::empty(S->symbols())) {
+ if (S->symbols().empty()) {
OS << "\n section empty\n";
continue;
}
@@ -446,248 +461,89 @@
}
}
-class JITLinkSlabAllocator final : public JITLinkMemoryManager {
-private:
- struct FinalizedAllocInfo {
- FinalizedAllocInfo(sys::MemoryBlock Mem,
- std::vector<shared::WrapperFunctionCall> DeallocActions)
- : Mem(Mem), DeallocActions(std::move(DeallocActions)) {}
- sys::MemoryBlock Mem;
- std::vector<shared::WrapperFunctionCall> DeallocActions;
- };
-
+// A memory mapper with a fake offset applied only used for -noexec testing
+class InProcessDeltaMapper final : public InProcessMemoryMapper {
public:
- static Expected<std::unique_ptr<JITLinkSlabAllocator>>
- Create(uint64_t SlabSize) {
- Error Err = Error::success();
- std::unique_ptr<JITLinkSlabAllocator> Allocator(
- new JITLinkSlabAllocator(SlabSize, Err));
- if (Err)
- return std::move(Err);
- return std::move(Allocator);
- }
+ InProcessDeltaMapper(size_t PageSize, uint64_t TargetAddr)
+ : InProcessMemoryMapper(PageSize), TargetMapAddr(TargetAddr),
+ DeltaAddr(0) {}
- void allocate(const JITLinkDylib *JD, LinkGraph &G,
- OnAllocatedFunction OnAllocated) override {
-
- // Local class for allocation.
- class IPMMAlloc : public InFlightAlloc {
- public:
- IPMMAlloc(JITLinkSlabAllocator &Parent, BasicLayout BL,
- sys::MemoryBlock StandardSegs, sys::MemoryBlock FinalizeSegs)
- : Parent(Parent), BL(std::move(BL)),
- StandardSegs(std::move(StandardSegs)),
- FinalizeSegs(std::move(FinalizeSegs)) {}
-
- void finalize(OnFinalizedFunction OnFinalized) override {
- if (auto Err = applyProtections()) {
- OnFinalized(std::move(Err));
- return;
- }
-
- auto DeallocActions = runFinalizeActions(BL.graphAllocActions());
- if (!DeallocActions) {
- OnFinalized(DeallocActions.takeError());
- return;
- }
-
- if (auto Err = Parent.freeBlock(FinalizeSegs)) {
- OnFinalized(
- joinErrors(std::move(Err), runDeallocActions(*DeallocActions)));
- return;
- }
-
- OnFinalized(FinalizedAlloc(ExecutorAddr::fromPtr(
- new FinalizedAllocInfo(StandardSegs, std::move(*DeallocActions)))));
- }
-
- void abandon(OnAbandonedFunction OnAbandoned) override {
- OnAbandoned(joinErrors(Parent.freeBlock(StandardSegs),
- Parent.freeBlock(FinalizeSegs)));
- }
-
- private:
- Error applyProtections() {
- for (auto &KV : BL.segments()) {
- const auto &Group = KV.first;
- auto &Seg = KV.second;
-
- auto Prot = toSysMemoryProtectionFlags(Group.getMemProt());
-
- uint64_t SegSize =
- alignTo(Seg.ContentSize + Seg.ZeroFillSize, Parent.PageSize);
- sys::MemoryBlock MB(Seg.WorkingMem, SegSize);
- if (auto EC = sys::Memory::protectMappedMemory(MB, Prot))
- return errorCodeToError(EC);
- if (Prot & sys::Memory::MF_EXEC)
- sys::Memory::InvalidateInstructionCache(MB.base(),
- MB.allocatedSize());
- }
- return Error::success();
- }
-
- JITLinkSlabAllocator &Parent;
- BasicLayout BL;
- sys::MemoryBlock StandardSegs;
- sys::MemoryBlock FinalizeSegs;
- };
-
- BasicLayout BL(G);
- auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(PageSize);
-
- if (!SegsSizes) {
- OnAllocated(SegsSizes.takeError());
- return;
- }
-
- char *AllocBase = nullptr;
- {
- std::lock_guard<std::mutex> Lock(SlabMutex);
-
- if (SegsSizes->total() > SlabRemaining.allocatedSize()) {
- OnAllocated(make_error<StringError>(
- "Slab allocator out of memory: request for " +
- formatv("{0:x}", SegsSizes->total()) +
- " bytes exceeds remaining capacity of " +
- formatv("{0:x}", SlabRemaining.allocatedSize()) + " bytes",
- inconvertibleErrorCode()));
- return;
- }
-
- AllocBase = reinterpret_cast<char *>(SlabRemaining.base());
- SlabRemaining =
- sys::MemoryBlock(AllocBase + SegsSizes->total(),
- SlabRemaining.allocatedSize() - SegsSizes->total());
- }
-
- sys::MemoryBlock StandardSegs(AllocBase, SegsSizes->StandardSegs);
- sys::MemoryBlock FinalizeSegs(AllocBase + SegsSizes->StandardSegs,
- SegsSizes->FinalizeSegs);
-
- auto NextStandardSegAddr = ExecutorAddr::fromPtr(StandardSegs.base());
- auto NextFinalizeSegAddr = ExecutorAddr::fromPtr(FinalizeSegs.base());
-
- LLVM_DEBUG({
- dbgs() << "JITLinkSlabAllocator allocated:\n";
- if (SegsSizes->StandardSegs)
- dbgs() << formatv(" [ {0:x16} -- {1:x16} ]", NextStandardSegAddr,
- NextStandardSegAddr + StandardSegs.allocatedSize())
- << " to stardard segs\n";
- else
- dbgs() << " no standard segs\n";
- if (SegsSizes->FinalizeSegs)
- dbgs() << formatv(" [ {0:x16} -- {1:x16} ]", NextFinalizeSegAddr,
- NextFinalizeSegAddr + FinalizeSegs.allocatedSize())
- << " to finalize segs\n";
- else
- dbgs() << " no finalize segs\n";
- });
-
- for (auto &KV : BL.segments()) {
- auto &Group = KV.first;
- auto &Seg = KV.second;
-
- auto &SegAddr =
- (Group.getMemDeallocPolicy() == MemDeallocPolicy::Standard)
- ? NextStandardSegAddr
- : NextFinalizeSegAddr;
-
- LLVM_DEBUG({
- dbgs() << " " << Group << " -> " << formatv("{0:x16}", SegAddr)
- << "\n";
- });
- Seg.WorkingMem = SegAddr.toPtr<char *>();
- Seg.Addr = SegAddr + SlabDelta;
-
- SegAddr += alignTo(Seg.ContentSize + Seg.ZeroFillSize, PageSize);
-
- // Zero out the zero-fill memory.
- if (Seg.ZeroFillSize != 0)
- memset(Seg.WorkingMem + Seg.ContentSize, 0, Seg.ZeroFillSize);
- }
-
- if (auto Err = BL.apply()) {
- OnAllocated(std::move(Err));
- return;
- }
-
- OnAllocated(std::unique_ptr<InProcessMemoryManager::InFlightAlloc>(
- new IPMMAlloc(*this, std::move(BL), std::move(StandardSegs),
- std::move(FinalizeSegs))));
- }
-
- void deallocate(std::vector<FinalizedAlloc> FinalizedAllocs,
- OnDeallocatedFunction OnDeallocated) override {
- Error Err = Error::success();
- for (auto &FA : FinalizedAllocs) {
- std::unique_ptr<FinalizedAllocInfo> FAI(
- FA.release().toPtr<FinalizedAllocInfo *>());
-
- // FIXME: Run dealloc actions.
-
- Err = joinErrors(std::move(Err), freeBlock(FAI->Mem));
- }
- OnDeallocated(std::move(Err));
- }
-
-private:
- JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
- ErrorAsOutParameter _(&Err);
-
- if (!SlabPageSize) {
+ static Expected<std::unique_ptr<InProcessDeltaMapper>> Create() {
+ size_t PageSize = SlabPageSize;
+ if (!PageSize) {
if (auto PageSizeOrErr = sys::Process::getPageSize())
PageSize = *PageSizeOrErr;
- else {
- Err = PageSizeOrErr.takeError();
- return;
- }
-
- if (PageSize == 0) {
- Err = make_error<StringError>("Page size is zero",
- inconvertibleErrorCode());
- return;
- }
- } else
- PageSize = SlabPageSize;
-
- if (!isPowerOf2_64(PageSize)) {
- Err = make_error<StringError>("Page size is not a power of 2",
- inconvertibleErrorCode());
- return;
+ else
+ return PageSizeOrErr.takeError();
}
- // Round slab request up to page size.
- SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
+ if (PageSize == 0)
+ return make_error<StringError>("Page size is zero",
+ inconvertibleErrorCode());
- const sys::Memory::ProtectionFlags ReadWrite =
- static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
- sys::Memory::MF_WRITE);
+ return std::make_unique<InProcessDeltaMapper>(PageSize, SlabAddress);
+ }
- std::error_code EC;
- SlabRemaining =
- sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
+ void reserve(size_t NumBytes, OnReservedFunction OnReserved) override {
+ InProcessMemoryMapper::reserve(
+ NumBytes, [this, OnReserved = std::move(OnReserved)](
+ Expected<ExecutorAddrRange> Result) mutable {
+ if (!Result)
+ return OnReserved(Result.takeError());
- if (EC) {
- Err = errorCodeToError(EC);
- return;
+ assert(DeltaAddr == 0 && "Overwriting previous offset");
+ if (TargetMapAddr != ~0ULL)
+ DeltaAddr = TargetMapAddr - Result->Start.getValue();
+ auto OffsetRange = ExecutorAddrRange(Result->Start + DeltaAddr,
+ Result->End + DeltaAddr);
+
+ OnReserved(OffsetRange);
+ });
+ }
+
+ char *prepare(ExecutorAddr Addr, size_t ContentSize) override {
+ return InProcessMemoryMapper::prepare(Addr - DeltaAddr, ContentSize);
+ }
+
+ void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override {
+ // Slide mapping based on delta and make all segments read-writable.
+ auto FixedAI = AI;
+ FixedAI.MappingBase -= DeltaAddr;
+ for (auto &Seg : FixedAI.Segments)
+ Seg.AG = AllocGroup(MemProt::Read | MemProt::Write,
+ Seg.AG.getMemDeallocPolicy());
+ InProcessMemoryMapper::initialize(
+ FixedAI, [this, OnInitialized = std::move(OnInitialized)](
+ Expected<ExecutorAddr> Result) mutable {
+ if (!Result)
+ return OnInitialized(Result.takeError());
+
+ OnInitialized(ExecutorAddr(Result->getValue() + DeltaAddr));
+ });
+ }
+
+ void deinitialize(ArrayRef<ExecutorAddr> Allocations,
+ OnDeinitializedFunction OnDeInitialized) override {
+ std::vector<ExecutorAddr> Addrs(Allocations.size());
+ for (const auto Base : Allocations) {
+ Addrs.push_back(Base - DeltaAddr);
}
- // Calculate the target address delta to link as-if slab were at
- // SlabAddress.
- if (SlabAddress != ~0ULL)
- SlabDelta = ExecutorAddr(SlabAddress) -
- ExecutorAddr::fromPtr(SlabRemaining.base());
+ InProcessMemoryMapper::deinitialize(Addrs, std::move(OnDeInitialized));
}
- Error freeBlock(sys::MemoryBlock MB) {
- // FIXME: Return memory to slab.
- return Error::success();
+ void release(ArrayRef<ExecutorAddr> Reservations,
+ OnReleasedFunction OnRelease) override {
+ std::vector<ExecutorAddr> Addrs(Reservations.size());
+ for (const auto Base : Reservations) {
+ Addrs.push_back(Base - DeltaAddr);
+ }
+ InProcessMemoryMapper::release(Addrs, std::move(OnRelease));
}
- std::mutex SlabMutex;
- sys::MemoryBlock SlabRemaining;
- uint64_t PageSize = 0;
- int64_t SlabDelta = 0;
+private:
+ uint64_t TargetMapAddr;
+ uint64_t DeltaAddr;
};
Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
@@ -713,14 +569,59 @@
return SlabSize * Units;
}
-static std::unique_ptr<JITLinkMemoryManager> createMemoryManager() {
- if (!SlabAllocateSizeString.empty()) {
- auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
- return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
- }
- return ExitOnErr(InProcessMemoryManager::Create());
+static std::unique_ptr<JITLinkMemoryManager> createInProcessMemoryManager() {
+ uint64_t SlabSize;
+#ifdef _WIN32
+ SlabSize = 1024 * 1024;
+#else
+ SlabSize = 1024 * 1024 * 1024;
+#endif
+
+ if (!SlabAllocateSizeString.empty())
+ SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
+
+ // If this is a -no-exec case and we're tweaking the slab address or size then
+ // use the delta mapper.
+ if (NoExec && (SlabAddress || SlabPageSize))
+ return ExitOnErr(
+ MapperJITLinkMemoryManager::CreateWithMapper<InProcessDeltaMapper>(
+ SlabSize));
+
+ // Otherwise use the standard in-process mapper.
+ return ExitOnErr(
+ MapperJITLinkMemoryManager::CreateWithMapper<InProcessMemoryMapper>(
+ SlabSize));
}
+Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
+createSharedMemoryManager(SimpleRemoteEPC &SREPC) {
+ SharedMemoryMapper::SymbolAddrs SAs;
+ if (auto Err = SREPC.getBootstrapSymbols(
+ {{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName},
+ {SAs.Reserve,
+ rt::ExecutorSharedMemoryMapperServiceReserveWrapperName},
+ {SAs.Initialize,
+ rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName},
+ {SAs.Deinitialize,
+ rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName},
+ {SAs.Release,
+ rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName}}))
+ return std::move(Err);
+
+#ifdef _WIN32
+ size_t SlabSize = 1024 * 1024;
+#else
+ size_t SlabSize = 1024 * 1024 * 1024;
+#endif
+
+ if (!SlabAllocateSizeString.empty())
+ SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
+
+ return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>(
+ SlabSize, SREPC, SAs);
+}
+
+
static Expected<MaterializationUnit::Interface>
getTestObjectFileInterface(Session &S, MemoryBufferRef O) {
@@ -804,10 +705,8 @@
LLVM_DEBUG(dbgs() << "Loading dylibs...\n");
for (const auto &Dylib : Dylibs) {
LLVM_DEBUG(dbgs() << " " << Dylib << "\n");
- auto G = orc::EPCDynamicLibrarySearchGenerator::Load(S.ES, Dylib.c_str());
- if (!G)
- return G.takeError();
- S.MainJD->addGenerator(std::move(*G));
+ if (auto Err = S.loadAndLinkDynamicLibrary(*S.MainJD, Dylib))
+ return Err;
}
return Error::success();
@@ -879,9 +778,13 @@
close(ToExecutor[ReadEnd]);
close(FromExecutor[WriteEnd]);
+ auto S = SimpleRemoteEPC::Setup();
+ if (UseSharedMemory)
+ S.CreateMemoryManager = createSharedMemoryManager;
+
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
- std::make_unique<DynamicThreadPoolTaskDispatcher>(),
- SimpleRemoteEPC::Setup(), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
+ std::make_unique<DynamicThreadPoolTaskDispatcher>(), std::move(S),
+ FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
#endif
}
@@ -965,9 +868,13 @@
if (!SockFD)
return SockFD.takeError();
+ auto S = SimpleRemoteEPC::Setup();
+ if (UseSharedMemory)
+ S.CreateMemoryManager = createSharedMemoryManager;
+
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
std::make_unique<DynamicThreadPoolTaskDispatcher>(),
- SimpleRemoteEPC::Setup(), *SockFD, *SockFD);
+ std::move(S), *SockFD, *SockFD);
#endif
}
@@ -1006,7 +913,7 @@
EPC = std::make_unique<SelfExecutorProcessControl>(
std::make_shared<SymbolStringPool>(),
std::make_unique<InPlaceTaskDispatcher>(), std::move(TT), *PageSize,
- createMemoryManager());
+ createInProcessMemoryManager());
}
Error Err = Error::success();
@@ -1038,10 +945,10 @@
Error notifyFailed(MaterializationResponsibility &MR) override {
return Error::success();
}
- Error notifyRemovingResources(ResourceKey K) override {
+ Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
return Error::success();
}
- void notifyTransferringResources(ResourceKey DstKey,
+ void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
ResourceKey SrcKey) override {}
private:
@@ -1061,6 +968,16 @@
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"),
+ {pointerToJITTargetAddress(llvm_jitlink_setTestResultOverride),
+ JITSymbolFlags::Exported}}})));
+ MainJD->addToLinkOrder(TestResultJD);
+ }
+
ExitOnErr(loadDylibs(*this));
auto &TT = ES.getExecutorProcessControl().getTargetTriple();
@@ -1086,6 +1003,21 @@
Err = P.takeError();
return;
}
+ } else if (TT.isOSBinFormatCOFF() && !OrcRuntime.empty()) {
+ auto LoadDynLibrary = [&, this](JITDylib &JD, StringRef DLLName) -> Error {
+ if (!DLLName.endswith_insensitive(".dll"))
+ return make_error<StringError>("DLLName not ending with .dll",
+ inconvertibleErrorCode());
+ return loadAndLinkDynamicLibrary(JD, DLLName);
+ };
+
+ if (auto P = COFFPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str(),
+ std::move(LoadDynLibrary)))
+ ES.setPlatform(std::move(*P));
+ else {
+ Err = P.takeError();
+ return;
+ }
} else if (TT.isOSBinFormatELF()) {
if (!NoExec)
ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
@@ -1145,7 +1077,7 @@
if (EPC.getTargetTriple().getObjectFormat() == Triple::MachO)
return registerMachOGraphInfo(*this, G);
- if (EPC.getTargetTriple().isOSWindows())
+ if (EPC.getTargetTriple().getObjectFormat() == Triple::COFF)
return registerCOFFGraphInfo(*this, G);
return make_error<StringError>("Unsupported object format for GOT/stub "
@@ -1185,6 +1117,37 @@
PassConfig.PostPrunePasses.push_back(addSelfRelocations);
}
+Expected<JITDylib *> Session::getOrLoadDynamicLibrary(StringRef LibPath) {
+ auto It = DynLibJDs.find(LibPath.str());
+ if (It != DynLibJDs.end()) {
+ return It->second;
+ }
+ auto G = EPCDynamicLibrarySearchGenerator::Load(ES, LibPath.data());
+ if (!G)
+ return G.takeError();
+ auto JD = &ES.createBareJITDylib(LibPath.str());
+
+ JD->addGenerator(std::move(*G));
+ DynLibJDs.emplace(LibPath.str(), JD);
+ LLVM_DEBUG({
+ dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPath
+ << "\n";
+ });
+ return JD;
+}
+
+Error Session::loadAndLinkDynamicLibrary(JITDylib &JD, StringRef LibPath) {
+ auto DL = getOrLoadDynamicLibrary(LibPath);
+ if (!DL)
+ return DL.takeError();
+ JD.addToLinkOrder(**DL);
+ LLVM_DEBUG({
+ dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName()
+ << "\n";
+ });
+ return Error::success();
+}
+
Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) {
auto FileInfoItr = FileInfos.find(FileName);
if (FileInfoItr == FileInfos.end())
@@ -1264,8 +1227,11 @@
auto Obj = ExitOnErr(
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
Triple TT = Obj->makeTriple();
- if (Magic == file_magic::coff_object)
+ if (Magic == file_magic::coff_object) {
+ // TODO: Move this to makeTriple() if possible.
+ TT.setObjectFormat(Triple::COFF);
TT.setOS(Triple::OSType::Win32);
+ }
return TT;
}
default:
@@ -1526,6 +1492,18 @@
return I;
}
+static SmallVector<StringRef, 5> getSearchPathsFromEnvVar(Session &S) {
+ // FIXME: Handle EPC environment.
+ SmallVector<StringRef, 5> PathVec;
+ auto TT = S.ES.getExecutorProcessControl().getTargetTriple();
+ if (TT.isOSBinFormatCOFF())
+ StringRef(getenv("PATH")).split(PathVec, ";");
+ else if (TT.isOSBinFormatELF())
+ StringRef(getenv("LD_LIBRARY_PATH")).split(PathVec, ":");
+
+ return PathVec;
+}
+
static Error addLibraries(Session &S,
const std::map<unsigned, JITDylib *> &IdxToJD) {
@@ -1563,13 +1541,15 @@
// 2. Collect library loads
struct LibraryLoad {
- StringRef LibName;
+ std::string LibName;
bool IsPath = false;
unsigned Position;
StringRef *CandidateExtensions;
enum { Standard, Hidden } Modifier;
};
- std::vector<LibraryLoad> LibraryLoads;
+
+ // Queue to load library as in the order as it appears in the argument list.
+ std::deque<LibraryLoad> LibraryLoadQueue;
// Add archive files from the inputs to LibraryLoads.
for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
InputFileItr != InputFileEnd; ++InputFileItr) {
@@ -1577,12 +1557,12 @@
if (!InputFile.endswith(".a") && !InputFile.endswith(".lib"))
continue;
LibraryLoad LL;
- LL.LibName = InputFile;
+ LL.LibName = InputFile.str();
LL.IsPath = true;
LL.Position = InputFiles.getPosition(InputFileItr - InputFiles.begin());
LL.CandidateExtensions = nullptr;
LL.Modifier = LibraryLoad::Standard;
- LibraryLoads.push_back(std::move(LL));
+ LibraryLoadQueue.push_back(std::move(LL));
}
// Add -load_hidden arguments to LibraryLoads.
@@ -1594,9 +1574,10 @@
LL.Position = LoadHidden.getPosition(LibItr - LoadHidden.begin());
LL.CandidateExtensions = nullptr;
LL.Modifier = LibraryLoad::Hidden;
- LibraryLoads.push_back(std::move(LL));
+ LibraryLoadQueue.push_back(std::move(LL));
}
StringRef StandardExtensions[] = {".so", ".dylib", ".dll", ".a", ".lib"};
+ StringRef DynLibExtensionsOnly[] = {".so", ".dylib", ".dll"};
StringRef ArchiveExtensionsOnly[] = {".a", ".lib"};
// Add -lx arguments to LibraryLoads.
@@ -1607,7 +1588,7 @@
LL.Position = Libraries.getPosition(LibItr - Libraries.begin());
LL.CandidateExtensions = StandardExtensions;
LL.Modifier = LibraryLoad::Standard;
- LibraryLoads.push_back(std::move(LL));
+ LibraryLoadQueue.push_back(std::move(LL));
}
// Add -hidden-lx arguments to LibraryLoads.
@@ -1620,7 +1601,7 @@
LibrariesHidden.getPosition(LibHiddenItr - LibrariesHidden.begin());
LL.CandidateExtensions = ArchiveExtensionsOnly;
LL.Modifier = LibraryLoad::Hidden;
- LibraryLoads.push_back(std::move(LL));
+ LibraryLoadQueue.push_back(std::move(LL));
}
// If there are any load-<modified> options then turn on flag overrides
@@ -1629,9 +1610,10 @@
S.ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
// Sort library loads by position in the argument list.
- llvm::sort(LibraryLoads, [](const LibraryLoad &LHS, const LibraryLoad &RHS) {
- return LHS.Position < RHS.Position;
- });
+ llvm::sort(LibraryLoadQueue,
+ [](const LibraryLoad &LHS, const LibraryLoad &RHS) {
+ return LHS.Position < RHS.Position;
+ });
// 3. Process library loads.
auto AddArchive = [&](const char *Path, const LibraryLoad &LL)
@@ -1647,13 +1629,37 @@
GetObjFileInterface = getObjectFileInterfaceHidden;
break;
}
- return StaticLibraryDefinitionGenerator::Load(
+ auto G = StaticLibraryDefinitionGenerator::Load(
S.ObjLayer, Path, S.ES.getExecutorProcessControl().getTargetTriple(),
std::move(GetObjFileInterface));
+ if (!G)
+ return G.takeError();
+
+ // Push additional dynamic libraries to search.
+ // Note that this mechanism only happens in COFF.
+ for (auto FileName : (*G)->getImportedDynamicLibraries()) {
+ LibraryLoad NewLL;
+ auto FileNameRef = StringRef(FileName);
+ if (!FileNameRef.endswith_insensitive(".dll"))
+ return make_error<StringError>(
+ "COFF Imported library not ending with dll extension?",
+ inconvertibleErrorCode());
+ NewLL.LibName = FileNameRef.drop_back(strlen(".dll")).str();
+ NewLL.Position = LL.Position;
+ NewLL.CandidateExtensions = DynLibExtensionsOnly;
+ NewLL.Modifier = LibraryLoad::Standard;
+ LibraryLoadQueue.push_front(std::move(NewLL));
+ }
+ return G;
};
- for (auto &LL : LibraryLoads) {
+ SmallVector<StringRef, 5> SystemSearchPaths;
+ if (SearchSystemLibrary.getValue())
+ SystemSearchPaths = getSearchPathsFromEnvVar(S);
+ while (!LibraryLoadQueue.empty()) {
bool LibFound = false;
+ auto LL = LibraryLoadQueue.front();
+ LibraryLoadQueue.pop_front();
auto &JD = *std::prev(IdxToJD.lower_bound(LL.Position))->second;
// If this is the name of a JITDylib then link against that.
@@ -1663,7 +1669,7 @@
}
if (LL.IsPath) {
- auto G = AddArchive(LL.LibName.str().c_str(), LL);
+ auto G = AddArchive(LL.LibName.c_str(), LL);
if (!G)
return createFileError(LL.LibName, G.takeError());
JD.addGenerator(std::move(*G));
@@ -1675,86 +1681,74 @@
}
// Otherwise look through the search paths.
- auto JDSearchPathsItr = JDSearchPaths.find(&JD);
- if (JDSearchPathsItr != JDSearchPaths.end()) {
- for (StringRef SearchPath : JDSearchPathsItr->second) {
- for (const char *LibExt : {".dylib", ".so", ".dll", ".a", ".lib"}) {
- SmallVector<char, 256> LibPath;
- LibPath.reserve(SearchPath.size() + strlen("lib") +
- LL.LibName.size() + strlen(LibExt) +
- 2); // +2 for pathsep, null term.
- llvm::copy(SearchPath, std::back_inserter(LibPath));
- if (StringRef(LibExt) != ".lib" && StringRef(LibExt) != ".dll")
- sys::path::append(LibPath, "lib" + LL.LibName + LibExt);
- else
- sys::path::append(LibPath, LL.LibName + LibExt);
- LibPath.push_back('\0');
+ auto CurJDSearchPaths = JDSearchPaths[&JD];
+ for (StringRef SearchPath :
+ concat<StringRef>(CurJDSearchPaths, SystemSearchPaths)) {
+ for (const char *LibExt : {".dylib", ".so", ".dll", ".a", ".lib"}) {
+ SmallVector<char, 256> LibPath;
+ LibPath.reserve(SearchPath.size() + strlen("lib") + LL.LibName.size() +
+ strlen(LibExt) + 2); // +2 for pathsep, null term.
+ llvm::copy(SearchPath, std::back_inserter(LibPath));
+ if (StringRef(LibExt) != ".lib" && StringRef(LibExt) != ".dll")
+ sys::path::append(LibPath, "lib" + LL.LibName + LibExt);
+ else
+ sys::path::append(LibPath, LL.LibName + LibExt);
+ LibPath.push_back('\0');
- // Skip missing or non-regular paths.
- if (sys::fs::get_file_type(LibPath.data()) !=
- sys::fs::file_type::regular_file) {
- continue;
- }
+ // Skip missing or non-regular paths.
+ if (sys::fs::get_file_type(LibPath.data()) !=
+ sys::fs::file_type::regular_file) {
+ continue;
+ }
- file_magic Magic;
- if (auto EC = identify_magic(LibPath, Magic)) {
- // If there was an error loading the file then skip it.
- LLVM_DEBUG({
- dbgs() << "Library search found \"" << LibPath
- << "\", but could not identify file type (" << EC.message()
- << "). Skipping.\n";
- });
- continue;
- }
+ file_magic Magic;
+ if (auto EC = identify_magic(LibPath, Magic)) {
+ // If there was an error loading the file then skip it.
+ LLVM_DEBUG({
+ dbgs() << "Library search found \"" << LibPath
+ << "\", but could not identify file type (" << EC.message()
+ << "). Skipping.\n";
+ });
+ continue;
+ }
- // We identified the magic. Assume that we can load it -- we'll reset
- // in the default case.
- LibFound = true;
- switch (Magic) {
- case file_magic::elf_shared_object:
- case file_magic::macho_dynamically_linked_shared_lib: {
- // TODO: On first reference to LibPath this should create a JITDylib
- // with a generator and add it to JD's links-against list. Subsquent
- // references should use the JITDylib created on the first
- // reference.
- auto G =
- EPCDynamicLibrarySearchGenerator::Load(S.ES, LibPath.data());
- if (!G)
- return G.takeError();
- LLVM_DEBUG({
- dbgs() << "Adding generator for dynamic library "
- << LibPath.data() << " to " << JD.getName() << "\n";
- });
- JD.addGenerator(std::move(*G));
- break;
- }
- case file_magic::archive:
- case file_magic::macho_universal_binary: {
- auto G = AddArchive(LibPath.data(), LL);
- if (!G)
- return G.takeError();
- JD.addGenerator(std::move(*G));
- LLVM_DEBUG({
- dbgs() << "Adding generator for static library " << LibPath.data()
- << " to " << JD.getName() << "\n";
- });
- break;
- }
- default:
- // This file isn't a recognized library kind.
- LLVM_DEBUG({
- dbgs() << "Library search found \"" << LibPath
- << "\", but file type is not supported. Skipping.\n";
- });
- LibFound = false;
- break;
- }
- if (LibFound)
- break;
+ // We identified the magic. Assume that we can load it -- we'll reset
+ // in the default case.
+ LibFound = true;
+ switch (Magic) {
+ case file_magic::pecoff_executable:
+ case file_magic::elf_shared_object:
+ case file_magic::macho_dynamically_linked_shared_lib: {
+ if (auto Err = S.loadAndLinkDynamicLibrary(JD, LibPath.data()))
+ return Err;
+ break;
+ }
+ case file_magic::archive:
+ case file_magic::macho_universal_binary: {
+ auto G = AddArchive(LibPath.data(), LL);
+ if (!G)
+ return G.takeError();
+ JD.addGenerator(std::move(*G));
+ LLVM_DEBUG({
+ dbgs() << "Adding generator for static library " << LibPath.data()
+ << " to " << JD.getName() << "\n";
+ });
+ break;
+ }
+ default:
+ // This file isn't a recognized library kind.
+ LLVM_DEBUG({
+ dbgs() << "Library search found \"" << LibPath
+ << "\", but file type is not supported. Skipping.\n";
+ });
+ LibFound = false;
+ break;
}
if (LibFound)
break;
}
+ if (LibFound)
+ break;
}
if (!LibFound)
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 9cac376..8d4c0d8 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.h
+++ b/src/llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.h
@@ -13,7 +13,6 @@
#ifndef LLVM_TOOLS_LLVM_JITLINK_LLVM_JITLINK_H
#define LLVM_TOOLS_LLVM_JITLINK_LLVM_JITLINK_H
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
@@ -53,9 +52,13 @@
StringMap<MemoryRegionInfo> GOTEntryInfos;
};
+ using DynLibJDMap = std::map<std::string, orc::JITDylib *>;
using SymbolInfoMap = StringMap<MemoryRegionInfo>;
using FileInfoMap = StringMap<FileInfo>;
+ Expected<orc::JITDylib *> getOrLoadDynamicLibrary(StringRef LibPath);
+ Error loadAndLinkDynamicLibrary(orc::JITDylib &JD, StringRef LibPath);
+
Expected<FileInfo &> findFileInfo(StringRef FileName);
Expected<MemoryRegionInfo &> findSectionInfo(StringRef FileName,
StringRef SectionName);
@@ -68,6 +71,8 @@
Expected<MemoryRegionInfo &> findSymbolInfo(StringRef SymbolName,
Twine ErrorMsgStem);
+ DynLibJDMap DynLibJDs;
+
SymbolInfoMap SymbolInfos;
FileInfoMap FileInfos;
uint64_t SizeBeforePruning = 0;
diff --git a/src/llvm-project/llvm/tools/llvm-jitlistener/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-jitlistener/CMakeLists.txt
index 61f8420..8592241 100644
--- a/src/llvm-project/llvm/tools/llvm-jitlistener/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-jitlistener/CMakeLists.txt
@@ -15,6 +15,7 @@
object
selectiondag
Support
+ TargetParser
ExecutionEngine
RuntimeDyld
Core
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 a06d107..f689645 100644
--- a/src/llvm-project/llvm/tools/llvm-libtool-darwin/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-libtool-darwin/CMakeLists.txt
@@ -3,6 +3,7 @@
Core
Object
Support
+ TargetParser
TextAPI
${LLVM_TARGETS_TO_BUILD}
)
diff --git a/src/llvm-project/llvm/tools/llvm-libtool-darwin/DependencyInfo.h b/src/llvm-project/llvm/tools/llvm-libtool-darwin/DependencyInfo.h
new file mode 100644
index 0000000..7b2f94b
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-libtool-darwin/DependencyInfo.h
@@ -0,0 +1,85 @@
+//===-- DependencyInfo.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <set>
+
+class DependencyInfo {
+public:
+ explicit DependencyInfo(std::string DependencyInfoPath)
+ : DependencyInfoPath(DependencyInfoPath) {}
+
+ virtual ~DependencyInfo(){};
+
+ virtual void addMissingInput(llvm::StringRef Path) {
+ NotFounds.insert(Path.str());
+ }
+
+ // Writes the dependencies to specified path. The content is first sorted by
+ // OpCode and then by the filename (in alphabetical order).
+ virtual void write(llvm::Twine Version,
+ const std::vector<std::string> &Inputs,
+ std::string Output) {
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(DependencyInfoPath, EC, llvm::sys::fs::OF_None);
+ if (EC) {
+ llvm::WithColor::defaultErrorHandler(llvm::createStringError(
+ EC,
+ "failed to write to " + DependencyInfoPath + ": " + EC.message()));
+ return;
+ }
+
+ auto AddDep = [&OS](DependencyInfoOpcode Opcode,
+ const llvm::StringRef &Path) {
+ OS << static_cast<uint8_t>(Opcode);
+ OS << Path;
+ OS << '\0';
+ };
+
+ AddDep(DependencyInfoOpcode::Tool, Version.str());
+
+ // Sort the input by its names.
+ std::vector<llvm::StringRef> InputNames;
+ InputNames.reserve(Inputs.size());
+ for (const auto &F : Inputs)
+ InputNames.push_back(F);
+ llvm::sort(InputNames);
+
+ for (const auto &In : InputNames)
+ AddDep(DependencyInfoOpcode::InputFound, In);
+
+ for (const std::string &F : NotFounds)
+ AddDep(DependencyInfoOpcode::InputMissing, F);
+
+ AddDep(DependencyInfoOpcode::Output, Output);
+ }
+
+private:
+ enum DependencyInfoOpcode : uint8_t {
+ Tool = 0x00,
+ InputFound = 0x10,
+ InputMissing = 0x11,
+ Output = 0x40,
+ };
+
+ const std::string DependencyInfoPath;
+ std::set<std::string> NotFounds;
+};
+
+// Subclass to avoid any overhead when not using this feature
+class DummyDependencyInfo : public DependencyInfo {
+public:
+ DummyDependencyInfo() : DependencyInfo("") {}
+ void addMissingInput(llvm::StringRef Path) override {}
+ void write(llvm::Twine Version, const std::vector<std::string> &Inputs,
+ std::string Output) override {}
+};
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 08b371e..3357afb0 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
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "DependencyInfo.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/ArchiveWriter.h"
@@ -87,6 +88,12 @@
" libraries"),
cl::Prefix, cl::cat(LibtoolCategory));
+static cl::opt<std::string> DependencyInfoPath(
+ "dependency_info",
+ cl::desc("Write an Xcode dependency info file describing the dependencies "
+ "of the created library"),
+ cl::cat(LibtoolCategory));
+
static cl::opt<bool>
VersionOption("V", cl::desc("Print the version number and exit"),
cl::cat(LibtoolCategory));
@@ -101,12 +108,16 @@
cl::cat(LibtoolCategory),
cl::init(false));
+static cl::opt<std::string> IgnoredSyslibRoot("syslibroot", cl::Hidden);
+
static const std::array<std::string, 3> StandardSearchDirs{
"/lib",
"/usr/lib",
"/usr/local/lib",
};
+std::unique_ptr<DependencyInfo> GlobalDependencyInfo;
+
struct Config {
bool Deterministic = true; // Updated by 'D' and 'U' modifiers.
uint32_t ArchCPUType;
@@ -114,20 +125,22 @@
};
static Expected<std::string> searchForFile(const Twine &FileName) {
-
auto FindLib =
- [FileName](ArrayRef<std::string> SearchDirs) -> Optional<std::string> {
+ [FileName](
+ ArrayRef<std::string> SearchDirs) -> std::optional<std::string> {
for (StringRef Dir : SearchDirs) {
SmallString<128> Path;
sys::path::append(Path, Dir, FileName);
if (sys::fs::exists(Path))
return std::string(Path);
+
+ GlobalDependencyInfo->addMissingInput(Path);
}
- return None;
+ return std::nullopt;
};
- Optional<std::string> Found = FindLib(LibrarySearchDirs);
+ std::optional<std::string> Found = FindLib(LibrarySearchDirs);
if (!Found)
Found = FindLib(StandardSearchDirs);
if (Found)
@@ -244,8 +257,8 @@
"This test makes sure NewArchiveMemberList is used by MembersData since "
"the following asserts test invariants required for MembersData.");
static_assert(
- !std::is_copy_constructible<
- decltype(NewArchiveMemberList::Members)::value_type>::value,
+ !std::is_copy_constructible_v<
+ decltype(NewArchiveMemberList::Members)::value_type>,
"MembersData::MembersPerArchitecture has a dependency on "
"MembersData::FileBuffers so it should not be able to "
"be copied on its own without FileBuffers. Unfortunately, "
@@ -253,8 +266,8 @@
"of a non-copyable type is itself non-copyable so we have to test the "
"actual type of the stored data (ie, value_type).");
static_assert(
- !std::is_copy_assignable<
- decltype(NewArchiveMemberList::Members)::value_type>::value,
+ !std::is_copy_assignable_v<
+ decltype(NewArchiveMemberList::Members)::value_type>,
"MembersData::MembersPerArchitecture has a dependency on "
"MembersData::FileBuffers so it should not be able to "
"be copied on its own without FileBuffers. Unfortunately, "
@@ -650,6 +663,11 @@
return C;
}
+ GlobalDependencyInfo =
+ DependencyInfoPath.empty()
+ ? std::make_unique<DummyDependencyInfo>()
+ : std::make_unique<DependencyInfo>(DependencyInfoPath);
+
if (OutputFile.empty()) {
std::string Error;
raw_string_ostream Stream(Error);
@@ -684,6 +702,9 @@
MachO::getArchitectureFromName(ArchType));
}
+ GlobalDependencyInfo->write("llvm-libtool-darwin " LLVM_VERSION_STRING,
+ InputFiles, OutputFile);
+
return C;
}
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 6585b19..32ab9fa 100644
--- a/src/llvm-project/llvm/tools/llvm-link/llvm-link.cpp
+++ b/src/llvm-project/llvm/tools/llvm-link/llvm-link.cpp
@@ -456,11 +456,12 @@
InitLLVM X(argc, argv);
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
+ cl::HideUnrelatedOptions({&LinkCategory, &getColorCategory()});
+ cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
+
LLVMContext Context;
Context.setDiagnosticHandler(std::make_unique<LLVMLinkDiagnosticHandler>(),
true);
- cl::HideUnrelatedOptions({&LinkCategory, &getColorCategory()});
- cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
if (!DisableDITypeMap)
Context.enableDebugTypeODRUniquing();
diff --git a/src/llvm-project/llvm/tools/llvm-lipo/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-lipo/CMakeLists.txt
index 2f582cb..342f9bf 100644
--- a/src/llvm-project/llvm/tools/llvm-lipo/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-lipo/CMakeLists.txt
@@ -3,6 +3,7 @@
Object
Option
Support
+ TargetParser
TextAPI
Core
BinaryFormat
@@ -16,6 +17,7 @@
llvm-lipo.cpp
DEPENDS
LipoOptsTableGen
+ GENERATE_DRIVER
)
if(LLVM_INSTALL_CCTOOLS_SYMLINKS)
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 43dd97e..074a526 100644
--- a/src/llvm-project/llvm/tools/llvm-lipo/llvm-lipo.cpp
+++ b/src/llvm-project/llvm/tools/llvm-lipo/llvm-lipo.cpp
@@ -28,8 +28,10 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/WithColor.h"
#include "llvm/TextAPI/Architecture.h"
+#include <optional>
using namespace llvm;
using namespace llvm::object;
@@ -71,26 +73,29 @@
#undef OPTION
};
-// LipoInfoTable below references LIPO_##PREFIX. OptionGroup has prefix nullptr.
-const char *const *LIPO_nullptr = nullptr;
-#define PREFIX(NAME, VALUE) const char *const LIPO_##NAME[] = VALUE;
+namespace lipo {
+#define PREFIX(NAME, VALUE) \
+ static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
#include "LipoOpts.inc"
#undef PREFIX
-const opt::OptTable::Info LipoInfoTable[] = {
+static constexpr opt::OptTable::Info LipoInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {LIPO_##PREFIX, NAME, HELPTEXT, \
- METAVAR, LIPO_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, LIPO_##GROUP, \
- LIPO_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, LIPO_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, LIPO_##GROUP, \
+ LIPO_##ALIAS, ALIASARGS, VALUES},
#include "LipoOpts.inc"
#undef OPTION
};
+} // namespace lipo
-class LipoOptTable : public opt::OptTable {
+class LipoOptTable : public opt::GenericOptTable {
public:
- LipoOptTable() : OptTable(LipoInfoTable) {}
+ LipoOptTable() : opt::GenericOptTable(lipo::LipoInfoTable) {}
};
enum class LipoAction {
@@ -104,7 +109,7 @@
};
struct InputFile {
- Optional<StringRef> ArchType;
+ std::optional<StringRef> ArchType;
StringRef FileName;
};
@@ -176,16 +181,14 @@
exit(EXIT_SUCCESS);
}
- for (auto Arg : InputArgs.filtered(LIPO_UNKNOWN))
+ for (auto *Arg : InputArgs.filtered(LIPO_UNKNOWN))
reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
- for (auto Arg : InputArgs.filtered(LIPO_INPUT))
- C.InputFiles.push_back({None, Arg->getValue()});
- for (auto Arg : InputArgs.filtered(LIPO_arch)) {
+ for (auto *Arg : InputArgs.filtered(LIPO_INPUT))
+ C.InputFiles.push_back({std::nullopt, Arg->getValue()});
+ for (auto *Arg : InputArgs.filtered(LIPO_arch)) {
validateArchitectureName(Arg->getValue(0));
- if (!Arg->getValue(1))
- reportError(
- "arch is missing an argument: expects -arch arch_type file_name");
+ assert(Arg->getValue(1) && "file_name is missing");
C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)});
}
@@ -195,7 +198,7 @@
if (InputArgs.hasArg(LIPO_output))
C.OutputFile = std::string(InputArgs.getLastArgValue(LIPO_output));
- for (auto Segalign : InputArgs.filtered(LIPO_segalign)) {
+ for (auto *Segalign : InputArgs.filtered(LIPO_segalign)) {
if (!Segalign->getValue(1))
reportError("segalign is missing an argument: expects -segalign "
"arch_type alignment_value");
@@ -239,7 +242,7 @@
std::string Buf;
raw_string_ostream OS(Buf);
OS << "only one of the following actions can be specified:";
- for (auto Arg : ActionArgs)
+ for (auto *Arg : ActionArgs)
OS << " " << Arg->getSpelling();
reportError(OS.str());
}
@@ -293,11 +296,8 @@
return C;
case LIPO_replace:
- for (auto Action : ActionArgs) {
- if (!Action->getValue(1))
- reportError(
- "replace is missing an argument: expects -replace arch_type "
- "file_name");
+ for (auto *Action : ActionArgs) {
+ assert(Action->getValue(1) && "file_name is missing");
validateArchitectureName(Action->getValue(0));
C.ReplacementFiles.push_back(
{StringRef(Action->getValue(0)), Action->getValue(1)});
@@ -430,7 +430,7 @@
Expected<Slice> SliceOrErr = createSliceFromIR(*IR, 0);
if (!SliceOrErr)
reportError(IR->getFileName(), SliceOrErr.takeError());
-
+
OS << SliceOrErr->getArchString() << " \n";
}
@@ -723,9 +723,13 @@
exit(EXIT_SUCCESS);
}
-int main(int argc, char **argv) {
+int llvm_lipo_main(int argc, char **argv) {
InitLLVM X(argc, argv);
- Config C = parseLipoOptions(makeArrayRef(argv + 1, argc));
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+
+ Config C = parseLipoOptions(ArrayRef(argv + 1, argc - 1));
LLVMContext LLVMCtx;
SmallVector<OwningBinary<Binary>, 1> InputBinaries =
readInputBinaries(LLVMCtx, C.InputFiles);
diff --git a/src/llvm-project/llvm/tools/llvm-lto/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-lto/CMakeLists.txt
index 93df852..988085b 100644
--- a/src/llvm-project/llvm/tools/llvm-lto/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-lto/CMakeLists.txt
@@ -14,6 +14,7 @@
Object
Support
Target
+ TargetParser
)
add_llvm_tool(llvm-lto
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 64c8c19..79e9d93 100644
--- a/src/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp
+++ b/src/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp
@@ -317,11 +317,11 @@
if (!CurrentActivity.empty())
OS << ' ' << CurrentActivity;
OS << ": ";
-
+
DiagnosticPrinterRawOStream DP(OS);
DI.print(DP);
OS << '\n';
-
+
if (DI.getSeverity() == DS_Error)
exit(1);
return true;
@@ -1099,7 +1099,9 @@
error("writing merged module failed.");
}
- auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
+ auto AddStream =
+ [&](size_t Task,
+ const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
std::string PartFilename = OutputFilename;
if (Parallelism != 1)
PartFilename += "." + utostr(Task);
diff --git a/src/llvm-project/llvm/tools/llvm-lto2/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-lto2/CMakeLists.txt
index dd09a34..3b4644d 100644
--- a/src/llvm-project/llvm/tools/llvm-lto2/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-lto2/CMakeLists.txt
@@ -13,6 +13,7 @@
Passes
Support
Target
+ TargetParser
)
add_llvm_tool(llvm-lto2
diff --git a/src/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp b/src/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp
index 87fe90a..09c74fc 100644
--- a/src/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/src/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -17,7 +17,6 @@
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Passes/PassPlugin.h"
@@ -131,7 +130,7 @@
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
-cl::opt<Optional<uint64_t>, false, remarks::HotnessThresholdParser>
+cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
RemarksHotnessThreshold(
"pass-remarks-hotness-threshold",
cl::desc("Minimum profile count required for an "
@@ -307,20 +306,9 @@
Conf.Freestanding = EnableFreestanding;
for (auto &PluginFN : PassPlugins)
Conf.PassPlugins.push_back(PluginFN);
- switch (CGOptLevel) {
- case '0':
- Conf.CGOptLevel = CodeGenOpt::None;
- break;
- case '1':
- Conf.CGOptLevel = CodeGenOpt::Less;
- break;
- case '2':
- Conf.CGOptLevel = CodeGenOpt::Default;
- break;
- case '3':
- Conf.CGOptLevel = CodeGenOpt::Aggressive;
- break;
- default:
+ if (auto Level = CodeGenOpt::parseLevel(CGOptLevel)) {
+ Conf.CGOptLevel = *Level;
+ } else {
llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n';
return 1;
}
@@ -411,7 +399,9 @@
if (HasErrors)
return 1;
- auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
+ auto AddStream =
+ [&](size_t Task,
+ const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
std::string Path = OutputFilename + "." + utostr(Task);
std::error_code EC;
@@ -420,8 +410,9 @@
return std::make_unique<CachedFileStream>(std::move(S), Path);
};
- auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
- *AddStream(Task)->OS << MB->getBuffer();
+ auto AddBuffer = [&](size_t Task, const Twine &ModuleName,
+ std::unique_ptr<MemoryBuffer> MB) {
+ *AddStream(Task, ModuleName)->OS << MB->getBuffer();
};
FileCache Cache;
diff --git a/src/llvm-project/llvm/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt
index d7835c83..ff9d381 100644
--- a/src/llvm-project/llvm/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt
@@ -5,6 +5,7 @@
MC
MCParser
Support
+ TargetParser
)
add_llvm_fuzzer(llvm-mc-assemble-fuzzer
diff --git a/src/llvm-project/llvm/tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt
index d1fbdf4..7e31941 100644
--- a/src/llvm-project/llvm/tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt
@@ -6,6 +6,7 @@
MCDisassembler
MCParser
Support
+ TargetParser
)
add_llvm_fuzzer(llvm-mc-disassemble-fuzzer
llvm-mc-disassemble-fuzzer.cpp
diff --git a/src/llvm-project/llvm/tools/llvm-mc/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-mc/CMakeLists.txt
index a18783e..f57356f 100644
--- a/src/llvm-project/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-mc/CMakeLists.txt
@@ -6,6 +6,7 @@
MC
MCParser
Support
+ TargetParser
)
add_llvm_tool(llvm-mc
diff --git a/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp b/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp
index ac55d05..2d18334 100644
--- a/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp
@@ -65,7 +65,7 @@
SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
SourceMgr::DK_Warning,
"potentially undefined instruction encoding");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MCDisassembler::Success:
Streamer.emitInstruction(Inst, STI);
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 aa380d3..dd5a66a 100644
--- a/src/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -76,8 +76,8 @@
cl::init(DebugCompressionType::None),
cl::desc("Choose DWARF debug sections compression:"),
cl::values(clEnumValN(DebugCompressionType::None, "none", "No compression"),
- clEnumValN(DebugCompressionType::Z, "zlib",
- "Use zlib compression")),
+ clEnumValN(DebugCompressionType::Zlib, "zlib", "Use zlib"),
+ clEnumValN(DebugCompressionType::Zstd, "zstd", "Use zstd")),
cl::cat(MCCategory));
static cl::opt<bool>
@@ -399,15 +399,15 @@
assert(MAI && "Unable to create target asm info!");
MAI->setRelaxELFRelocations(RelaxELFRel);
-
if (CompressDebugSections != DebugCompressionType::None) {
- if (!compression::zlib::isAvailable()) {
+ if (const char *Reason = compression::getReasonIfUnsupported(
+ compression::formatFor(CompressDebugSections))) {
WithColor::error(errs(), ProgName)
- << "build tools with zlib to enable -compress-debug-sections";
+ << "--compress-debug-sections: " << Reason;
return 1;
}
- MAI->setCompressDebugSections(CompressDebugSections);
}
+ MAI->setCompressDebugSections(CompressDebugSections);
MAI->setPreserveAsmComments(PreserveComments);
// Package up features to be passed to target/subtarget
diff --git a/src/llvm-project/llvm/tools/llvm-mca/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-mca/CMakeLists.txt
index 0a0cd2e..878a05c 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-mca/CMakeLists.txt
@@ -10,6 +10,7 @@
MC
MCParser
Support
+ TargetParser
)
add_llvm_tool(llvm-mca
diff --git a/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp b/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp
index 7662538..c91ed75 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp
@@ -16,11 +16,6 @@
namespace llvm {
namespace mca {
-CodeRegions::CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {
- // Create a default region for the input code sequence.
- Regions.emplace_back(std::make_unique<CodeRegion>("", SMLoc()));
-}
-
bool CodeRegion::isLocInRange(SMLoc Loc) const {
if (RangeEnd.isValid() && Loc.getPointer() > RangeEnd.getPointer())
return false;
@@ -29,7 +24,19 @@
return true;
}
-void CodeRegions::beginRegion(StringRef Description, SMLoc Loc) {
+void CodeRegions::addInstruction(const MCInst &Instruction) {
+ SMLoc Loc = Instruction.getLoc();
+ for (UniqueCodeRegion &Region : Regions)
+ if (Region->isLocInRange(Loc))
+ Region->addInstruction(Instruction);
+}
+
+AnalysisRegions::AnalysisRegions(llvm::SourceMgr &S) : CodeRegions(S) {
+ // Create a default region for the input code sequence.
+ Regions.emplace_back(std::make_unique<CodeRegion>("", SMLoc()));
+}
+
+void AnalysisRegions::beginRegion(StringRef Description, SMLoc Loc) {
if (ActiveRegions.empty()) {
// Remove the default region if there is at least one user defined region.
// By construction, only the default region has an invalid start location.
@@ -44,17 +51,17 @@
if (It != ActiveRegions.end()) {
const CodeRegion &R = *Regions[It->second];
if (Description.empty()) {
- SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
"found multiple overlapping anonymous regions");
- SM.PrintMessage(R.startLoc(), SourceMgr::DK_Note,
+ SM.PrintMessage(R.startLoc(), llvm::SourceMgr::DK_Note,
"Previous anonymous region was defined here");
FoundErrors = true;
return;
}
- SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
"overlapping regions cannot have the same name");
- SM.PrintMessage(R.startLoc(), SourceMgr::DK_Note,
+ SM.PrintMessage(R.startLoc(), llvm::SourceMgr::DK_Note,
"region " + Description + " was previously defined here");
FoundErrors = true;
return;
@@ -65,7 +72,7 @@
Regions.emplace_back(std::make_unique<CodeRegion>(Description, Loc));
}
-void CodeRegions::endRegion(StringRef Description, SMLoc Loc) {
+void AnalysisRegions::endRegion(StringRef Description, SMLoc Loc) {
if (Description.empty()) {
// Special case where there is only one user defined region,
// and this LLVM-MCA-END directive doesn't provide a region name.
@@ -94,22 +101,73 @@
}
FoundErrors = true;
- SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
"found an invalid region end directive");
if (!Description.empty()) {
- SM.PrintMessage(Loc, SourceMgr::DK_Note,
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
"unable to find an active region named " + Description);
} else {
- SM.PrintMessage(Loc, SourceMgr::DK_Note,
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
"unable to find an active anonymous region");
}
}
-void CodeRegions::addInstruction(const MCInst &Instruction) {
- SMLoc Loc = Instruction.getLoc();
- for (UniqueCodeRegion &Region : Regions)
- if (Region->isLocInRange(Loc))
- Region->addInstruction(Instruction);
+InstrumentRegions::InstrumentRegions(llvm::SourceMgr &S) : CodeRegions(S) {}
+
+void InstrumentRegions::beginRegion(StringRef Description, SMLoc Loc,
+ SharedInstrument I) {
+ if (Description.empty()) {
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
+ "anonymous instrumentation regions are not permitted");
+ FoundErrors = true;
+ return;
+ }
+
+ auto It = ActiveRegions.find(Description);
+ if (It != ActiveRegions.end()) {
+ const CodeRegion &R = *Regions[It->second];
+ SM.PrintMessage(
+ Loc, llvm::SourceMgr::DK_Error,
+ "overlapping instrumentation regions cannot be of the same kind");
+ SM.PrintMessage(R.startLoc(), llvm::SourceMgr::DK_Note,
+ "instrumentation region " + Description +
+ " was previously defined here");
+ FoundErrors = true;
+ return;
+ }
+
+ ActiveRegions[Description] = Regions.size();
+ Regions.emplace_back(std::make_unique<InstrumentRegion>(Description, Loc, I));
+}
+
+void InstrumentRegions::endRegion(StringRef Description, SMLoc Loc) {
+ auto It = ActiveRegions.find(Description);
+ if (It != ActiveRegions.end()) {
+ Regions[It->second]->setEndLocation(Loc);
+ ActiveRegions.erase(It);
+ return;
+ }
+
+ FoundErrors = true;
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
+ "found an invalid instrumentation region end directive");
+ if (!Description.empty()) {
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
+ "unable to find an active instrumentation region named " +
+ Description);
+ }
+}
+
+const SmallVector<SharedInstrument>
+InstrumentRegions::getActiveInstruments(SMLoc Loc) const {
+ SmallVector<SharedInstrument> AI;
+ for (auto &R : Regions) {
+ if (R->isLocInRange(Loc)) {
+ InstrumentRegion *IR = static_cast<InstrumentRegion *>(R.get());
+ AI.emplace_back(IR->getInstrument());
+ }
+ }
+ return AI;
}
} // namespace mca
diff --git a/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.h b/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.h
index 0e1e02a..b5b2f3a 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.h
+++ b/src/llvm-project/llvm/tools/llvm-mca/CodeRegion.h
@@ -7,7 +7,8 @@
//===----------------------------------------------------------------------===//
/// \file
///
-/// This file implements class CodeRegion and CodeRegions.
+/// This file implements class CodeRegion and CodeRegions, InstrumentRegion,
+/// AnalysisRegions, and InstrumentRegions.
///
/// A CodeRegion describes a region of assembly code guarded by special LLVM-MCA
/// comment directives.
@@ -25,8 +26,32 @@
/// description; internally, regions are described by a range of source
/// locations (SMLoc objects).
///
-/// An instruction (a MCInst) is added to a region R only if its location is in
-/// range [R.RangeStart, R.RangeEnd].
+/// An instruction (a MCInst) is added to a CodeRegion R only if its
+/// location is in range [R.RangeStart, R.RangeEnd].
+///
+/// A InstrumentRegion describes a region of assembly code guarded by
+/// special LLVM-MCA comment directives.
+///
+/// # LLVM-MCA-<INSTRUMENTATION_TYPE> <data>
+/// ... ## asm
+///
+/// where INSTRUMENTATION_TYPE is a type defined in llvm and expects to use
+/// data.
+///
+/// A comment starting with substring LLVM-MCA-<INSTRUMENTATION_TYPE>
+/// brings data into scope for llvm-mca to use in its analysis for
+/// all following instructions.
+///
+/// If the same INSTRUMENTATION_TYPE is found later in the instruction list,
+/// then the original InstrumentRegion will be automatically ended,
+/// and a new InstrumentRegion will begin.
+///
+/// If there are comments containing the different INSTRUMENTATION_TYPEs,
+/// then both data sets remain available. In contrast with a CodeRegion,
+/// an InstrumentRegion does not need a comment to end the region.
+//
+// An instruction (a MCInst) is added to an InstrumentRegion R only
+// if its location is in range [R.RangeStart, R.RangeEnd].
//
//===----------------------------------------------------------------------===//
@@ -38,6 +63,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MCA/CustomBehaviour.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
@@ -81,9 +107,31 @@
llvm::StringRef getDescription() const { return Description; }
};
+/// Alias AnalysisRegion with CodeRegion since CodeRegionGenerator
+/// is absract and AnalysisRegionGenerator operates on AnalysisRegions
+using AnalysisRegion = CodeRegion;
+
+/// A CodeRegion that contains instrumentation that can be used
+/// in analysis of the region.
+class InstrumentRegion : public CodeRegion {
+ /// Instrument for this region.
+ SharedInstrument Instrument;
+
+public:
+ InstrumentRegion(llvm::StringRef Desc, llvm::SMLoc Start, SharedInstrument I)
+ : CodeRegion(Desc, Start), Instrument(I) {}
+
+public:
+ SharedInstrument getInstrument() const { return Instrument; }
+};
+
class CodeRegionParseError final : public Error {};
class CodeRegions {
+ CodeRegions(const CodeRegions &) = delete;
+ CodeRegions &operator=(const CodeRegions &) = delete;
+
+protected:
// A source manager. Used by the tool to generate meaningful warnings.
llvm::SourceMgr &SM;
@@ -92,11 +140,8 @@
llvm::StringMap<unsigned> ActiveRegions;
bool FoundErrors;
- CodeRegions(const CodeRegions &) = delete;
- CodeRegions &operator=(const CodeRegions &) = delete;
-
public:
- CodeRegions(llvm::SourceMgr &S);
+ CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {}
typedef std::vector<UniqueCodeRegion>::iterator iterator;
typedef std::vector<UniqueCodeRegion>::const_iterator const_iterator;
@@ -106,8 +151,6 @@
const_iterator begin() const { return Regions.cbegin(); }
const_iterator end() const { return Regions.cend(); }
- void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc);
- void endRegion(llvm::StringRef Description, llvm::SMLoc Loc);
void addInstruction(const llvm::MCInst &Instruction);
llvm::SourceMgr &getSourceMgr() const { return SM; }
@@ -122,6 +165,28 @@
}
bool isValid() const { return !FoundErrors; }
+
+ bool isRegionActive(llvm::StringRef Description) const {
+ return ActiveRegions.find(Description) != ActiveRegions.end();
+ }
+};
+
+struct AnalysisRegions : public CodeRegions {
+ AnalysisRegions(llvm::SourceMgr &S);
+
+ void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc);
+ void endRegion(llvm::StringRef Description, llvm::SMLoc Loc);
+};
+
+struct InstrumentRegions : public CodeRegions {
+ InstrumentRegions(llvm::SourceMgr &S);
+
+ void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
+ SharedInstrument Instrument);
+ void endRegion(llvm::StringRef Description, llvm::SMLoc Loc);
+
+ const SmallVector<SharedInstrument>
+ getActiveInstruments(llvm::SMLoc Loc) const;
};
} // namespace mca
diff --git a/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
index cdecfba..b8e10fa 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
@@ -16,7 +16,6 @@
#include "CodeRegionGenerator.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCTargetOptions.h"
@@ -30,15 +29,6 @@
// This virtual dtor serves as the anchor for the CodeRegionGenerator class.
CodeRegionGenerator::~CodeRegionGenerator() {}
-// A comment consumer that parses strings. The only valid tokens are strings.
-class MCACommentConsumer : public AsmCommentConsumer {
-public:
- CodeRegions &Regions;
-
- MCACommentConsumer(CodeRegions &R) : Regions(R) {}
- void HandleComment(SMLoc Loc, StringRef CommentText) override;
-};
-
// This class provides the callbacks that occur when parsing input assembly.
class MCStreamerWrapper final : public MCStreamer {
CodeRegions &Regions;
@@ -58,9 +48,9 @@
}
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- unsigned ByteAlignment) override {}
+ Align ByteAlignment) override {}
void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
- uint64_t Size = 0, unsigned ByteAlignment = 0,
+ uint64_t Size = 0, Align ByteAlignment = Align(1),
SMLoc Loc = SMLoc()) override {}
void emitGPRel32Value(const MCExpr *Value) override {}
void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
@@ -73,7 +63,53 @@
}
};
-void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) {
+Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
+ const std::unique_ptr<MCInstPrinter> &IP) {
+ MCTargetOptions Opts;
+ Opts.PreserveAsmComments = false;
+ CodeRegions &Regions = getRegions();
+ MCStreamerWrapper Str(Ctx, Regions);
+
+ // Need to initialize an MCTargetStreamer otherwise
+ // certain asm directives will cause a segfault.
+ // Using nulls() so that anything emitted by the MCTargetStreamer
+ // doesn't show up in the llvm-mca output.
+ raw_ostream &OSRef = nulls();
+ formatted_raw_ostream FOSRef(OSRef);
+ TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(),
+ /*IsVerboseAsm=*/true);
+
+ // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
+ // comments.
+ std::unique_ptr<MCAsmParser> Parser(
+ createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
+ MCAsmLexer &Lexer = Parser->getLexer();
+ MCACommentConsumer *CCP = getCommentConsumer();
+ Lexer.setCommentConsumer(CCP);
+ // Enable support for MASM literal numbers (example: 05h, 101b).
+ Lexer.setLexMasmIntegers(true);
+
+ std::unique_ptr<MCTargetAsmParser> TAP(
+ TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
+ if (!TAP)
+ return make_error<StringError>(
+ "This target does not support assembly parsing.",
+ inconvertibleErrorCode());
+ Parser->setTargetParser(*TAP);
+ Parser->Run(false);
+
+ if (CCP->hadErr())
+ return make_error<StringError>("There was an error parsing comments.",
+ inconvertibleErrorCode());
+
+ // Set the assembler dialect from the input. llvm-mca will use this as the
+ // default dialect when printing reports.
+ AssemblerDialect = Parser->getAssemblerDialect();
+ return Regions;
+}
+
+void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
+ StringRef CommentText) {
// Skip empty comments.
StringRef Comment(CommentText);
if (Comment.empty())
@@ -107,44 +143,66 @@
Regions.beginRegion(Comment, Loc);
}
-Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
- const std::unique_ptr<MCInstPrinter> &IP) {
- MCTargetOptions Opts;
- Opts.PreserveAsmComments = false;
- MCStreamerWrapper Str(Ctx, Regions);
+void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,
+ StringRef CommentText) {
+ // Skip empty comments.
+ StringRef Comment(CommentText);
+ if (Comment.empty())
+ return;
- // Need to initialize an MCTargetStreamer otherwise
- // certain asm directives will cause a segfault.
- // Using nulls() so that anything emitted by the MCTargetStreamer
- // doesn't show up in the llvm-mca output.
- raw_ostream &OSRef = nulls();
- formatted_raw_ostream FOSRef(OSRef);
- TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(),
- /*IsVerboseAsm=*/true);
+ // Skip spaces and tabs.
+ unsigned Position = Comment.find_first_not_of(" \t");
+ if (Position >= Comment.size())
+ // We reached the end of the comment. Bail out.
+ return;
+ Comment = Comment.drop_front(Position);
- // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
- // comments.
- std::unique_ptr<MCAsmParser> Parser(
- createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
- MCAsmLexer &Lexer = Parser->getLexer();
- MCACommentConsumer CC(Regions);
- Lexer.setCommentConsumer(&CC);
- // Enable support for MASM literal numbers (example: 05h, 101b).
- Lexer.setLexMasmIntegers(true);
+ // Bail out if not an MCA style comment
+ if (!Comment.consume_front("LLVM-MCA-"))
+ return;
- std::unique_ptr<MCTargetAsmParser> TAP(
- TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
- if (!TAP)
- return make_error<StringError>(
- "This target does not support assembly parsing.",
- inconvertibleErrorCode());
- Parser->setTargetParser(*TAP);
- Parser->Run(false);
+ // Skip AnalysisRegion comments
+ if (Comment.consume_front("BEGIN") || Comment.consume_front("END"))
+ return;
- // Set the assembler dialect from the input. llvm-mca will use this as the
- // default dialect when printing reports.
- AssemblerDialect = Parser->getAssemblerDialect();
- return Regions;
+ if (IM.shouldIgnoreInstruments())
+ return;
+
+ auto [InstrumentKind, Data] = Comment.split(" ");
+
+ // An error if not of the form LLVM-MCA-TARGET-KIND
+ if (!IM.supportsInstrumentType(InstrumentKind)) {
+ if (InstrumentKind.empty())
+ SM.PrintMessage(
+ Loc, llvm::SourceMgr::DK_Error,
+ "No instrumentation kind was provided in LLVM-MCA comment");
+ else
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
+ "Unknown instrumentation type in LLVM-MCA comment: " +
+ InstrumentKind);
+ FoundError = true;
+ return;
+ }
+
+ SharedInstrument I = IM.createInstrument(InstrumentKind, Data);
+ if (!I) {
+ if (Data.empty())
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
+ "Failed to create " + InstrumentKind +
+ " instrument with no data");
+ else
+ SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
+ "Failed to create " + InstrumentKind +
+ " instrument with data: " + Data);
+ FoundError = true;
+ return;
+ }
+
+ // End InstrumentType region if one is open
+ if (Regions.isRegionActive(InstrumentKind))
+ Regions.endRegion(InstrumentKind, Loc);
+ // Start new instrumentation region
+ Regions.beginRegion(InstrumentKind, Loc, I);
}
} // namespace mca
diff --git a/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h b/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h
index ac02131..88621ed 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h
+++ b/src/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h
@@ -19,8 +19,10 @@
#include "CodeRegion.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCA/CustomBehaviour.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/SourceMgr.h"
#include <memory>
@@ -28,24 +30,96 @@
namespace llvm {
namespace mca {
-/// This class is responsible for parsing the input given to the llvm-mca
-/// driver, and converting that into a CodeRegions instance.
-class CodeRegionGenerator {
+class MCACommentConsumer : public AsmCommentConsumer {
protected:
- CodeRegions Regions;
- CodeRegionGenerator(const CodeRegionGenerator &) = delete;
- CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete;
+ bool FoundError;
public:
- CodeRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
- virtual ~CodeRegionGenerator();
- virtual Expected<const CodeRegions &>
- parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
+ MCACommentConsumer() : FoundError(false) {}
+
+ bool hadErr() const { return FoundError; }
};
-/// This class is responsible for parsing input ASM and generating
-/// a CodeRegions instance.
-class AsmCodeRegionGenerator final : public CodeRegionGenerator {
+/// A comment consumer that parses strings. The only valid tokens are strings.
+class AnalysisRegionCommentConsumer : public MCACommentConsumer {
+ AnalysisRegions &Regions;
+
+public:
+ AnalysisRegionCommentConsumer(AnalysisRegions &R) : Regions(R) {}
+
+ /// Parses a comment. It begins a new region if it is of the form
+ /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END.
+ /// Regions can be optionally named if they are of the form
+ /// LLVM-MCA-BEGIN <name> or LLVM-MCA-END <name>. Subregions are
+ /// permitted, but a region that begins while another region is active
+ /// must be ended before the outer region is ended. If thre is only one
+ /// active region, LLVM-MCA-END does not need to provide a name.
+ void HandleComment(SMLoc Loc, StringRef CommentText) override;
+};
+
+/// A comment consumer that parses strings to create InstrumentRegions.
+/// The only valid tokens are strings.
+class InstrumentRegionCommentConsumer : public MCACommentConsumer {
+ llvm::SourceMgr &SM;
+
+ InstrumentRegions &Regions;
+
+ InstrumentManager &IM;
+
+public:
+ InstrumentRegionCommentConsumer(llvm::SourceMgr &SM, InstrumentRegions &R,
+ InstrumentManager &IM)
+ : SM(SM), Regions(R), IM(IM) {}
+
+ /// Parses a comment. It begins a new region if it is of the form
+ /// LLVM-MCA-<INSTRUMENTATION_TYPE> <data> where INSTRUMENTATION_TYPE
+ /// is a valid InstrumentKind. If there is already an active
+ /// region of type INSTRUMENATION_TYPE, then it will end the active
+ /// one and begin a new one using the new data.
+ void HandleComment(SMLoc Loc, StringRef CommentText) override;
+};
+
+/// This abstract class is responsible for parsing the input given to
+/// the llvm-mca driver, and converting that into a CodeRegions instance.
+class CodeRegionGenerator {
+protected:
+ CodeRegionGenerator(const CodeRegionGenerator &) = delete;
+ CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete;
+ virtual Expected<const CodeRegions &>
+ parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
+
+public:
+ CodeRegionGenerator() {}
+ virtual ~CodeRegionGenerator();
+};
+
+/// Abastract CodeRegionGenerator with AnalysisRegions member
+class AnalysisRegionGenerator : public virtual CodeRegionGenerator {
+protected:
+ AnalysisRegions Regions;
+
+public:
+ AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
+
+ virtual Expected<const AnalysisRegions &>
+ parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
+};
+
+/// Abstract CodeRegionGenerator with InstrumentRegionsRegions member
+class InstrumentRegionGenerator : public virtual CodeRegionGenerator {
+protected:
+ InstrumentRegions Regions;
+
+public:
+ InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
+
+ virtual Expected<const InstrumentRegions &>
+ parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
+};
+
+/// This abstract class is responsible for parsing input ASM and
+/// generating a CodeRegions instance.
+class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
const Target &TheTarget;
MCContext &Ctx;
const MCAsmInfo &MAI;
@@ -54,17 +128,77 @@
unsigned AssemblerDialect; // This is set during parsing.
public:
- AsmCodeRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
- const MCAsmInfo &A, const MCSubtargetInfo &S,
- const MCInstrInfo &I)
- : CodeRegionGenerator(SM), TheTarget(T), Ctx(C), MAI(A), STI(S), MCII(I),
- AssemblerDialect(0) {}
+ AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A,
+ const MCSubtargetInfo &S, const MCInstrInfo &I)
+ : TheTarget(T), Ctx(C), MAI(A), STI(S), MCII(I), AssemblerDialect(0) {}
+
+ virtual MCACommentConsumer *getCommentConsumer() = 0;
+ virtual CodeRegions &getRegions() = 0;
unsigned getAssemblerDialect() const { return AssemblerDialect; }
Expected<const CodeRegions &>
parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override;
};
+class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
+ public AsmCodeRegionGenerator {
+ AnalysisRegionCommentConsumer CC;
+
+public:
+ AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
+ const MCAsmInfo &A, const MCSubtargetInfo &S,
+ const MCInstrInfo &I)
+ : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
+ CC(Regions) {}
+
+ MCACommentConsumer *getCommentConsumer() override { return &CC; };
+ CodeRegions &getRegions() override { return Regions; };
+
+ Expected<const AnalysisRegions &>
+ parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
+ Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
+ if (!RegionsOrErr)
+ return RegionsOrErr.takeError();
+ else
+ return static_cast<const AnalysisRegions &>(*RegionsOrErr);
+ }
+
+ Expected<const CodeRegions &>
+ parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
+ return AsmCodeRegionGenerator::parseCodeRegions(IP);
+ }
+};
+
+class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator,
+ public AsmCodeRegionGenerator {
+ InstrumentRegionCommentConsumer CC;
+
+public:
+ AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM,
+ MCContext &C, const MCAsmInfo &A,
+ const MCSubtargetInfo &S, const MCInstrInfo &I,
+ InstrumentManager &IM)
+ : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
+ CC(SM, Regions, IM) {}
+
+ MCACommentConsumer *getCommentConsumer() override { return &CC; };
+ CodeRegions &getRegions() override { return Regions; };
+
+ Expected<const InstrumentRegions &>
+ parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
+ Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
+ if (!RegionsOrErr)
+ return RegionsOrErr.takeError();
+ else
+ return static_cast<const InstrumentRegions &>(*RegionsOrErr);
+ }
+
+ Expected<const CodeRegions &>
+ parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
+ return AsmCodeRegionGenerator::parseCodeRegions(IP);
+ }
+};
+
} // namespace mca
} // namespace llvm
diff --git a/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
index d3f9738..257fdca 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
@@ -71,7 +71,7 @@
TempStream << ' ';
if (IIVDEntry.RThroughput) {
- double RT = IIVDEntry.RThroughput.value();
+ double RT = *IIVDEntry.RThroughput;
TempStream << format("%.2f", RT) << ' ';
if (RT < 10.0)
TempStream << " ";
diff --git a/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h b/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h
index c35d316..bddd01a 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h
+++ b/src/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h
@@ -61,7 +61,7 @@
struct InstructionInfoViewData {
unsigned NumMicroOpcodes = 0;
unsigned Latency = 0;
- Optional<double> RThroughput = 0.0;
+ std::optional<double> RThroughput = 0.0;
bool mayLoad = false;
bool mayStore = false;
bool hasUnmodeledSideEffects = false;
diff --git a/src/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp b/src/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp
index 6f7b74f..73c3418 100644
--- a/src/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -231,6 +231,12 @@
"Disable custom behaviour (use the default class which does nothing)."),
cl::cat(ViewOptions), cl::init(false));
+static cl::opt<bool> DisableInstrumentManager(
+ "disable-im",
+ cl::desc("Disable instrumentation manager (use the default class which "
+ "ignores instruments.)."),
+ cl::cat(ViewOptions), cl::init(false));
+
namespace {
const Target *getTarget(const char *ProgName) {
@@ -316,6 +322,9 @@
InitializeAllAsmParsers();
InitializeAllTargetMCAs();
+ // Register the Target and CPU printer for --version.
+ cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);
+
// Enable printing of available targets when flag --version is specified.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
@@ -407,7 +416,7 @@
// Need to initialize an MCInstPrinter as it is
// required for initializing the MCTargetStreamer
- // which needs to happen within the CRG.parseCodeRegions() call below.
+ // which needs to happen within the CRG.parseAnalysisRegions() call below.
// Without an MCTargetStreamer, certain assembly directives can trigger a
// segfault. (For example, the .cv_fpo_proc directive on x86 will segfault if
// we don't initialize the MCTargetStreamer.)
@@ -424,9 +433,10 @@
}
// Parse the input and create CodeRegions that llvm-mca can analyze.
- mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII);
- Expected<const mca::CodeRegions &> RegionsOrErr =
- CRG.parseCodeRegions(std::move(IPtemp));
+ mca::AsmAnalysisRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI,
+ *MCII);
+ Expected<const mca::AnalysisRegions &> RegionsOrErr =
+ CRG.parseAnalysisRegions(std::move(IPtemp));
if (!RegionsOrErr) {
if (auto Err =
handleErrors(RegionsOrErr.takeError(), [](const StringError &E) {
@@ -437,7 +447,7 @@
}
return 1;
}
- const mca::CodeRegions &Regions = *RegionsOrErr;
+ const mca::AnalysisRegions &Regions = *RegionsOrErr;
// Early exit if errors were found by the code region parsing logic.
if (!Regions.isValid())
@@ -448,6 +458,39 @@
return 1;
}
+ std::unique_ptr<mca::InstrumentManager> IM;
+ if (!DisableInstrumentManager) {
+ IM = std::unique_ptr<mca::InstrumentManager>(
+ TheTarget->createInstrumentManager(*STI, *MCII));
+ }
+ if (!IM) {
+ // If the target doesn't have its own IM implemented (or the -disable-cb
+ // flag is set) then we use the base class (which does nothing).
+ IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);
+ }
+
+ // Parse the input and create InstrumentRegion that llvm-mca
+ // can use to improve analysis.
+ mca::AsmInstrumentRegionGenerator IRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI,
+ *MCII, *IM);
+ Expected<const mca::InstrumentRegions &> InstrumentRegionsOrErr =
+ IRG.parseInstrumentRegions(std::move(IPtemp));
+ if (!InstrumentRegionsOrErr) {
+ if (auto Err = handleErrors(InstrumentRegionsOrErr.takeError(),
+ [](const StringError &E) {
+ WithColor::error() << E.getMessage() << '\n';
+ })) {
+ // Default case.
+ WithColor::error() << toString(std::move(Err)) << '\n';
+ }
+ return 1;
+ }
+ const mca::InstrumentRegions &InstrumentRegions = *InstrumentRegionsOrErr;
+
+ // Early exit if errors were found by the instrumentation parsing logic.
+ if (!InstrumentRegions.isValid())
+ return 1;
+
// Now initialize the output file.
auto OF = getOutputStream();
if (std::error_code EC = OF.getError()) {
@@ -491,7 +534,7 @@
}
// Create an instruction builder.
- mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get());
+ mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM);
// Create a context to control ownership of the pipeline hardware.
mca::Context MCA(*MRI, *STI);
@@ -512,7 +555,7 @@
assert(MAB && "Unable to create asm backend!");
json::Object JSONOutput;
- for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) {
+ for (const std::unique_ptr<mca::AnalysisRegion> &Region : Regions) {
// Skip empty code regions.
if (Region->empty())
continue;
@@ -527,8 +570,12 @@
SmallVector<std::unique_ptr<mca::Instruction>> LoweredSequence;
for (const MCInst &MCI : Insts) {
+ SMLoc Loc = MCI.getLoc();
+ const SmallVector<mca::SharedInstrument> Instruments =
+ InstrumentRegions.getActiveInstruments(Loc);
+
Expected<std::unique_ptr<mca::Instruction>> Inst =
- IB.createInstruction(MCI);
+ IB.createInstruction(MCI, Instruments);
if (!Inst) {
if (auto NewE = handleErrors(
Inst.takeError(),
diff --git a/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt
index 7c79039..2b2a116a 100644
--- a/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-ml/CMakeLists.txt
@@ -7,6 +7,7 @@
MCParser
Option
Support
+ TargetParser
)
set(LLVM_TARGET_DEFINITIONS Opts.td)
diff --git a/src/llvm-project/llvm/tools/llvm-ml/Disassembler.cpp b/src/llvm-project/llvm/tools/llvm-ml/Disassembler.cpp
index 6a96c88..72d88d9 100644
--- a/src/llvm-project/llvm/tools/llvm-ml/Disassembler.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ml/Disassembler.cpp
@@ -61,7 +61,7 @@
SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
SourceMgr::DK_Warning,
"potentially undefined instruction encoding");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MCDisassembler::Success:
Streamer.emitInstruction(Inst, STI);
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 12cd727..0af4854 100644
--- a/src/llvm-project/llvm/tools/llvm-ml/llvm-ml.cpp
+++ b/src/llvm-project/llvm/tools/llvm-ml/llvm-ml.cpp
@@ -44,6 +44,7 @@
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include <ctime>
+#include <optional>
using namespace llvm;
using namespace llvm::opt;
@@ -59,11 +60,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -75,9 +79,9 @@
#undef OPTION
};
-class MLOptTable : public opt::OptTable {
+class MLOptTable : public opt::GenericOptTable {
public:
- MLOptTable() : OptTable(InfoTable, /*IgnoreCase=*/false) {}
+ MLOptTable() : opt::GenericOptTable(InfoTable, /*IgnoreCase=*/false) {}
};
} // namespace
@@ -201,7 +205,7 @@
MLOptTable T;
unsigned MissingArgIndex, MissingArgCount;
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
opt::InputArgList InputArgs =
T.ParseArgs(ArgsArr, MissingArgIndex, MissingArgCount);
@@ -303,7 +307,7 @@
std::vector<std::string> IncludeDirs =
InputArgs.getAllArgValues(OPT_include_path);
if (!InputArgs.hasArg(OPT_ignore_include_envvar)) {
- if (llvm::Optional<std::string> IncludeEnvVar =
+ if (std::optional<std::string> IncludeEnvVar =
llvm::sys::Process::GetEnv("INCLUDE")) {
SmallVector<StringRef, 8> Dirs;
StringRef(*IncludeEnvVar)
diff --git a/src/llvm-project/llvm/tools/llvm-mt/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-mt/CMakeLists.txt
index e4e9946..dd427a2 100644
--- a/src/llvm-project/llvm/tools/llvm-mt/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-mt/CMakeLists.txt
@@ -11,4 +11,7 @@
add_llvm_tool(llvm-mt
llvm-mt.cpp
+ DEPENDS
+ MtTableGen
+ GENERATE_DRIVER
)
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 f938396..d460fd6 100644
--- a/src/llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp
+++ b/src/llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp
@@ -41,11 +41,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -57,9 +60,9 @@
#undef OPTION
};
-class CvtResOptTable : public opt::OptTable {
+class CvtResOptTable : public opt::GenericOptTable {
public:
- CvtResOptTable() : OptTable(InfoTable, true) {}
+ CvtResOptTable() : opt::GenericOptTable(InfoTable, true) {}
};
} // namespace
@@ -79,12 +82,12 @@
});
}
-int main(int Argc, const char **Argv) {
+int llvm_mt_main(int Argc, char **Argv) {
InitLLVM X(Argc, Argv);
CvtResOptTable T;
unsigned MAI, MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
@@ -150,9 +153,9 @@
bool Same = false;
if (OutBuffOrErr) {
const std::unique_ptr<MemoryBuffer> &FileBuffer = *OutBuffOrErr;
- Same = std::equal(OutputBuffer->getBufferStart(),
- OutputBuffer->getBufferEnd(),
- FileBuffer->getBufferStart());
+ Same = std::equal(
+ OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
+ FileBuffer->getBufferStart(), FileBuffer->getBufferEnd());
}
if (!Same) {
#if LLVM_ON_UNIX
diff --git a/src/llvm-project/llvm/tools/llvm-nm/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-nm/CMakeLists.txt
index 4ad5370..cd69712 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
+ TargetParser
TextAPI
)
@@ -21,6 +22,7 @@
DEPENDS
NmOptsTableGen
intrinsics_gen
+ GENERATE_DRIVER
)
if(LLVM_INSTALL_BINUTILS_SYMLINKS)
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 f0def8b..55319d0 100644
--- a/src/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/src/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/Demangle/Demangle.h"
@@ -39,6 +40,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
@@ -62,11 +64,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -78,9 +83,11 @@
#undef OPTION
};
-class NmOptTable : public opt::OptTable {
+class NmOptTable : public opt::GenericOptTable {
public:
- NmOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+ NmOptTable() : opt::GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
};
enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
@@ -611,7 +618,7 @@
};
static const char *getDarwinStabString(uint8_t NType) {
- for (auto I : makeArrayRef(DarwinStabNames))
+ for (auto I : ArrayRef(DarwinStabNames))
if (I.NType == NType)
return I.Name;
return nullptr;
@@ -645,25 +652,25 @@
outs() << format(" %02x", NType);
}
-static Optional<std::string> demangle(StringRef Name) {
+static std::optional<std::string> demangle(StringRef Name) {
std::string Demangled;
if (nonMicrosoftDemangle(Name.str().c_str(), Demangled))
return Demangled;
- return None;
+ return std::nullopt;
}
-static Optional<std::string> demangleXCOFF(StringRef Name) {
+static std::optional<std::string> demangleXCOFF(StringRef Name) {
if (Name.empty() || Name[0] != '.')
return demangle(Name);
Name = Name.drop_front();
- Optional<std::string> DemangledName = demangle(Name);
+ std::optional<std::string> DemangledName = demangle(Name);
if (DemangledName)
return "." + *DemangledName;
- return None;
+ return std::nullopt;
}
-static Optional<std::string> demangleMachO(StringRef Name) {
+static std::optional<std::string> demangleMachO(StringRef Name) {
if (!Name.empty() && Name[0] == '_')
Name = Name.drop_front();
return demangle(Name);
@@ -760,12 +767,12 @@
std::string Name = S.Name;
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if (Demangle) {
- function_ref<Optional<std::string>(StringRef)> Fn = ::demangle;
+ function_ref<std::optional<std::string>(StringRef)> Fn = ::demangle;
if (Obj.isXCOFF())
Fn = demangleXCOFF;
if (Obj.isMachO())
Fn = demangleMachO;
- if (Optional<std::string> Opt = Fn(S.Name))
+ if (std::optional<std::string> Opt = Fn(S.Name))
Name = *Opt;
}
@@ -2287,17 +2294,15 @@
}
// Delete symbols which should not be printed from SymolList.
- SymbolList.erase(
- llvm::remove_if(SymbolList,
- [](const NMSymbol &s) { return !s.shouldPrint(); }),
- SymbolList.end());
+ llvm::erase_if(SymbolList,
+ [](const NMSymbol &s) { return !s.shouldPrint(); });
sortSymbolList(SymbolList);
SymbolList.erase(std::unique(SymbolList.begin(), SymbolList.end()),
SymbolList.end());
printExportSymbolList(SymbolList);
}
-int main(int argc, char **argv) {
+int llvm_nm_main(int argc, char **argv) {
InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
@@ -2373,17 +2378,32 @@
UndefinedOnly = Args.hasArg(OPT_undefined_only);
WithoutAliases = Args.hasArg(OPT_without_aliases);
- StringRef Mode = Args.getLastArgValue(OPT_X, "any");
- if (Mode == "32")
- BitMode = BitModeTy::Bit32;
- else if (Mode == "64")
- BitMode = BitModeTy::Bit64;
- else if (Mode == "32_64")
- BitMode = BitModeTy::Bit32_64;
- else if (Mode == "any")
+ // Get BitMode from enviornment variable "OBJECT_MODE" for AIX OS, if
+ // specified.
+ Triple HostTriple(sys::getProcessTriple());
+ if (HostTriple.isOSAIX()) {
+ BitMode = StringSwitch<BitModeTy>(getenv("OBJECT_MODE"))
+ .Case("32", BitModeTy::Bit32)
+ .Case("64", BitModeTy::Bit64)
+ .Case("32_64", BitModeTy::Bit32_64)
+ .Case("any", BitModeTy::Any)
+ .Default(BitModeTy::Bit32);
+ } else
BitMode = BitModeTy::Any;
- else
- error("-X value should be one of: 32, 64, 32_64, (default) any");
+
+ if (Arg *A = Args.getLastArg(OPT_X)) {
+ StringRef Mode = A->getValue();
+ if (Mode == "32")
+ BitMode = BitModeTy::Bit32;
+ else if (Mode == "64")
+ BitMode = BitModeTy::Bit64;
+ else if (Mode == "32_64")
+ BitMode = BitModeTy::Bit32_64;
+ else if (Mode == "any")
+ BitMode = BitModeTy::Any;
+ else
+ error("-X value should be one of: 32, 64, 32_64, (default) any");
+ }
// Mach-O specific options.
FormatMachOasHex = Args.hasArg(OPT_x);
@@ -2459,4 +2479,5 @@
if (HadError)
return 1;
+ return 0;
}
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-objcopy/CMakeLists.txt
index ca94d4a..1c73a17 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/CMakeLists.txt
@@ -3,6 +3,7 @@
ObjCopy
Option
Support
+ TargetParser
MC
BinaryFormat
)
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 7db1e79..577b837 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "ObjcopyOptions.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@@ -37,32 +36,29 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
+namespace objcopy_opt {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "ObjcopyOpts.inc"
#undef PREFIX
-const opt::OptTable::Info ObjcopyInfoTable[] = {
+static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {OBJCOPY_##PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- OBJCOPY_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- OBJCOPY_##GROUP, \
- OBJCOPY_##ALIAS, \
- ALIASARGS, \
- VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OBJCOPY_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OBJCOPY_##GROUP, \
+ OBJCOPY_##ALIAS, ALIASARGS, VALUES},
#include "ObjcopyOpts.inc"
#undef OPTION
};
+} // namespace objcopy_opt
-class ObjcopyOptTable : public opt::OptTable {
+class ObjcopyOptTable : public opt::GenericOptTable {
public:
- ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {
+ ObjcopyOptTable() : opt::GenericOptTable(objcopy_opt::ObjcopyInfoTable) {
setGroupedShortOptions(true);
}
};
@@ -76,15 +72,19 @@
#undef OPTION
};
+namespace install_name_tool {
+
#define PREFIX(NAME, VALUE) \
- const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE;
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "InstallNameToolOpts.inc"
#undef PREFIX
-const opt::OptTable::Info InstallNameToolInfoTable[] = {
+static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {INSTALL_NAME_TOOL_##PREFIX, \
+ {PREFIX, \
NAME, \
HELPTEXT, \
METAVAR, \
@@ -99,10 +99,12 @@
#include "InstallNameToolOpts.inc"
#undef OPTION
};
+} // namespace install_name_tool
-class InstallNameToolOptTable : public opt::OptTable {
+class InstallNameToolOptTable : public opt::GenericOptTable {
public:
- InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {}
+ InstallNameToolOptTable()
+ : GenericOptTable(install_name_tool::InstallNameToolInfoTable) {}
};
enum BitcodeStripID {
@@ -114,14 +116,19 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const BITCODE_STRIP_##NAME[] = VALUE;
+namespace bitcode_strip {
+
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "BitcodeStripOpts.inc"
#undef PREFIX
-const opt::OptTable::Info BitcodeStripInfoTable[] = {
+static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {BITCODE_STRIP_##PREFIX, \
+ {PREFIX, \
NAME, \
HELPTEXT, \
METAVAR, \
@@ -136,10 +143,12 @@
#include "BitcodeStripOpts.inc"
#undef OPTION
};
+} // namespace bitcode_strip
-class BitcodeStripOptTable : public opt::OptTable {
+class BitcodeStripOptTable : public opt::GenericOptTable {
public:
- BitcodeStripOptTable() : OptTable(BitcodeStripInfoTable) {}
+ BitcodeStripOptTable()
+ : opt::GenericOptTable(bitcode_strip::BitcodeStripInfoTable) {}
};
enum StripID {
@@ -151,24 +160,31 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
+namespace strip {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "StripOpts.inc"
#undef PREFIX
-const opt::OptTable::Info StripInfoTable[] = {
+static constexpr opt::OptTable::Info StripInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {STRIP_##PREFIX, NAME, HELPTEXT, \
- METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, STRIP_##GROUP, \
- STRIP_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, STRIP_##GROUP, \
+ STRIP_##ALIAS, ALIASARGS, VALUES},
#include "StripOpts.inc"
#undef OPTION
};
+} // namespace strip
-class StripOptTable : public opt::OptTable {
+class StripOptTable : public opt::GenericOptTable {
public:
- StripOptTable() : OptTable(StripInfoTable) { setGroupedShortOptions(true); }
+ StripOptTable() : GenericOptTable(strip::StripInfoTable) {
+ setGroupedShortOptions(true);
+ }
};
} // namespace
@@ -226,7 +242,7 @@
if (NameAndFlags.size() > 1) {
Expected<SectionFlag> ParsedFlagSet =
- parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
+ parseSectionFlagSet(ArrayRef(NameAndFlags).drop_front());
if (!ParsedFlagSet)
return ParsedFlagSet.takeError();
SR.NewFlags = *ParsedFlagSet;
@@ -559,9 +575,8 @@
ObjcopyOptTable T;
const char *const *DashDash =
- std::find_if(RawArgsArr.begin(), RawArgsArr.end(),
- [](StringRef Str) { return Str == "--"; });
- ArrayRef<const char *> ArgsArr = makeArrayRef(RawArgsArr.begin(), DashDash);
+ llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; });
+ ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash);
if (DashDash != RawArgsArr.end())
DashDash = std::next(DashDash);
@@ -587,11 +602,11 @@
SmallVector<const char *, 2> Positional;
- for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
return createStringError(errc::invalid_argument, "unknown argument '%s'",
Arg->getAsString(InputArgs).c_str());
- for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_INPUT))
Positional.push_back(Arg->getValue());
std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));
@@ -721,17 +736,18 @@
if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) {
Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue())
- .Case("zlib", DebugCompressionType::Z)
+ .Case("zlib", DebugCompressionType::Zlib)
+ .Case("zstd", DebugCompressionType::Zstd)
.Default(DebugCompressionType::None);
- if (Config.CompressionType == DebugCompressionType::None)
+ if (Config.CompressionType == DebugCompressionType::None) {
return createStringError(
errc::invalid_argument,
"invalid or unsupported --compress-debug-sections format: %s",
A->getValue());
- if (!compression::zlib::isAvailable())
- return createStringError(
- errc::invalid_argument,
- "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
+ }
+ if (const char *Reason = compression::getReasonIfUnsupported(
+ compression::formatFor(Config.CompressionType)))
+ return createStringError(errc::invalid_argument, Reason);
}
Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
@@ -754,7 +770,7 @@
if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
Config.ExtractPartition = Arg->getValue();
- for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
if (!StringRef(Arg->getValue()).contains('='))
return createStringError(errc::invalid_argument,
"bad format for --redefine-sym");
@@ -765,12 +781,12 @@
Old2New.first.str().c_str());
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
Arg->getValue()))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
Expected<SectionRename> SR =
parseRenameSectionValue(StringRef(Arg->getValue()));
if (!SR)
@@ -780,14 +796,14 @@
"multiple renames of section '%s'",
SR->OriginalName.str().c_str());
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
parseSetSectionAttribute("--set-section-alignment", Arg->getValue());
if (!NameAndAlign)
return NameAndAlign.takeError();
Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
Expected<SectionFlagsUpdate> SFU =
parseSetSectionFlagValue(Arg->getValue());
if (!SFU)
@@ -798,7 +814,7 @@
"--set-section-flags set multiple times for section '%s'",
SFU->Name.str().c_str());
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {
Expected<std::pair<StringRef, uint64_t>> NameAndType =
parseSetSectionAttribute("--set-section-type", Arg->getValue());
if (!NameAndType)
@@ -822,24 +838,24 @@
return Err("type");
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_section))
if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_section))
if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_only_section))
if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_add_section)) {
if (Error Err = loadNewSectionData(Arg->getValue(), "--add-section",
Config.AddSection))
return std::move(Err);
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_update_section)) {
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_update_section)) {
if (Error Err = loadNewSectionData(Arg->getValue(), "--update-section",
Config.UpdateSection))
return std::move(Err);
@@ -879,66 +895,66 @@
Config.StripDebug = true;
ELFConfig.KeepFileSymbols = true;
}
- for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
Arg->getValue(), SymbolMatchStyle,
ErrorCallback))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
Arg->getValue(), SymbolMatchStyle,
ErrorCallback))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
Arg->getValue(), SymbolMatchStyle,
ErrorCallback))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
Arg->getValue(), SymbolMatchStyle,
ErrorCallback))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
Arg->getValue(), SymbolMatchStyle,
ErrorCallback))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
if (Error E =
Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
Arg->getValue(), SymbolMatchStyle,
ErrorCallback))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
+ for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
if (Error E =
addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
SymbolMatchStyle, ErrorCallback))
@@ -964,7 +980,7 @@
return createStringError(errc::invalid_argument,
"--preserve-dates requires a file");
- for (auto Arg : InputArgs)
+ for (auto *Arg : InputArgs)
if (Arg->getOption().matches(OBJCOPY_set_start)) {
auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
if (!EAddr)
@@ -993,11 +1009,6 @@
"--decompress-debug-sections");
}
- if (Config.DecompressDebugSections && !compression::zlib::isAvailable())
- return createStringError(
- errc::invalid_argument,
- "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
-
if (Config.ExtractPartition && Config.ExtractMainPartition)
return createStringError(errc::invalid_argument,
"cannot specify --extract-partition together with "
@@ -1045,13 +1056,13 @@
exit(0);
}
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
+ for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
MachOConfig.RPathToAdd.push_back(Arg->getValue());
for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))
MachOConfig.RPathToPrepend.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
+ for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
StringRef RPath = Arg->getValue();
// Cannot add and delete the same rpath at the same time.
@@ -1126,10 +1137,10 @@
InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);
SmallVector<StringRef, 2> Positional;
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
+ for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
return createStringError(errc::invalid_argument, "unknown argument '%s'",
Arg->getAsString(InputArgs).c_str());
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
+ for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
Positional.push_back(Arg->getValue());
if (Positional.empty())
return createStringError(errc::invalid_argument, "no input file specified");
@@ -1198,7 +1209,15 @@
// We only support -r for now, which removes all bitcode sections and
// the __LLVM segment if it's now empty.
cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(
+ "__LLVM,__asm", MatchStyle::Literal, ErrorCallback)));
+ cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(
+ "__LLVM,__bitcode", MatchStyle::Literal, ErrorCallback)));
+ cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(
"__LLVM,__bundle", MatchStyle::Literal, ErrorCallback)));
+ cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(
+ "__LLVM,__cmdline", MatchStyle::Literal, ErrorCallback)));
+ cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(
+ "__LLVM,__swift_cmdline", MatchStyle::Literal, ErrorCallback)));
MachOConfig.EmptySegmentsToRemove.insert("__LLVM");
DC.CopyConfigs.push_back(std::move(ConfigMgr));
@@ -1212,9 +1231,8 @@
objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr,
function_ref<Error(Error)> ErrorCallback) {
const char *const *DashDash =
- std::find_if(RawArgsArr.begin(), RawArgsArr.end(),
- [](StringRef Str) { return Str == "--"; });
- ArrayRef<const char *> ArgsArr = makeArrayRef(RawArgsArr.begin(), DashDash);
+ llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; });
+ ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash);
if (DashDash != RawArgsArr.end())
DashDash = std::next(DashDash);
@@ -1240,10 +1258,10 @@
}
SmallVector<StringRef, 2> Positional;
- for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
+ for (auto *Arg : InputArgs.filtered(STRIP_UNKNOWN))
return createStringError(errc::invalid_argument, "unknown argument '%s'",
Arg->getAsString(InputArgs).c_str());
- for (auto Arg : InputArgs.filtered(STRIP_INPUT))
+ for (auto *Arg : InputArgs.filtered(STRIP_INPUT))
Positional.push_back(Arg->getValue());
std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));
@@ -1286,22 +1304,22 @@
ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined);
- for (auto Arg : InputArgs.filtered(STRIP_keep_section))
+ for (auto *Arg : InputArgs.filtered(STRIP_keep_section))
if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(STRIP_remove_section))
+ for (auto *Arg : InputArgs.filtered(STRIP_remove_section))
if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
+ for (auto *Arg : InputArgs.filtered(STRIP_strip_symbol))
if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
- for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
+ for (auto *Arg : InputArgs.filtered(STRIP_keep_symbol))
if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
diff --git a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index d3713b5..0fddd44 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -33,7 +33,7 @@
: Joined<["--"], "compress-debug-sections=">,
MetaVarName<"format">,
HelpText<"Compress DWARF debug sections using specified format. Supported "
- "formats: zlib">;
+ "formats: zlib, zstd. Select zlib if <format> is omitted">;
def : Flag<["--"], "compress-debug-sections">, Alias<compress_debug_sections>,
AliasArgs<["zlib"]>;
def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">,
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 aa26215..a24cd88 100644
--- a/src/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -240,7 +240,7 @@
: cl::TokenizeGNUCommandLine,
NewArgv);
- auto Args = makeArrayRef(NewArgv).drop_front();
+ auto Args = ArrayRef(NewArgv).drop_front();
Expected<DriverConfig> DriverConfig = getDriverConfig(Args);
if (!DriverConfig) {
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt
index 2179728..c8c07ca 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-objdump/CMakeLists.txt
@@ -12,6 +12,7 @@
Option
Support
Symbolize
+ TargetParser
)
set(LLVM_TARGET_DEFINITIONS ObjdumpOpts.td)
@@ -36,6 +37,8 @@
OtoolOptsTableGen
)
+target_link_libraries(llvm-objdump PRIVATE LLVMDebuginfod)
+
if(LLVM_HAVE_LIBXAR)
target_link_libraries(llvm-objdump PRIVATE ${XAR_LIB})
endif()
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
index e65762e..3bc7d3c 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -10,7 +10,7 @@
/// This file implements the COFF-specific dumper for llvm-objdump.
/// It outputs the Win64 EH data structures as plain text.
/// The encoding of the unwind codes is described in MSDN:
-/// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
+/// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
///
//===----------------------------------------------------------------------===//
@@ -102,7 +102,7 @@
};
printU16("Magic", Hdr.Magic, "%04x");
- printOptionalEnumName(Hdr.Magic, makeArrayRef(PEHeaderMagic));
+ printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
outs() << '\n';
print("MajorLinkerVersion", Hdr.MajorLinkerVersion);
print("MinorLinkerVersion", Hdr.MinorLinkerVersion);
@@ -127,7 +127,7 @@
printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");
printU32("CheckSum", Hdr.CheckSum, "%08x\n");
printU16("Subsystem", Hdr.Subsystem, "%08x");
- printOptionalEnumName(Hdr.Subsystem, makeArrayRef(PEWindowsSubsystem));
+ printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));
outs() << '\n';
printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");
@@ -173,7 +173,7 @@
"Reserved",
};
outs() << "\nThe Data Directory\n";
- for (uint32_t I = 0; I != array_lengthof(DirName); ++I) {
+ for (uint32_t I = 0; I != std::size(DirName); ++I) {
uint32_t Addr = 0, Size = 0;
if (const data_directory *Data = Obj.getDataDirectory(I)) {
Addr = Data->RelativeVirtualAddress;
@@ -194,6 +194,8 @@
case UOP_SetFPReg: return "UOP_SetFPReg";
case UOP_SaveNonVol: return "UOP_SaveNonVol";
case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
+ case UOP_Epilog: return "UOP_Epilog";
+ case UOP_SpareCode: return "UOP_SpareCode";
case UOP_SaveXMM128: return "UOP_SaveXMM128";
case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
case UOP_PushMachFrame: return "UOP_PushMachFrame";
@@ -234,9 +236,11 @@
return 1;
case UOP_SaveNonVol:
case UOP_SaveXMM128:
+ case UOP_Epilog:
return 2;
case UOP_SaveNonVolBig:
case UOP_SaveXMM128Big:
+ case UOP_SpareCode:
return 3;
case UOP_AllocLarge:
return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
@@ -305,7 +309,7 @@
<< " remaining in buffer";
return ;
}
- printUnwindCode(makeArrayRef(I, E));
+ printUnwindCode(ArrayRef(I, E));
I += UsedSlots;
}
}
@@ -651,7 +655,7 @@
if (UI->NumCodes)
outs() << " Unwind Codes:\n";
- printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
+ printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
outs() << "\n";
outs().flush();
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
index 61676b4..b98b45e 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -248,13 +248,16 @@
outs() << " NOTE ";
break;
case ELF::PT_OPENBSD_BOOTDATA:
- outs() << " OPENBSD_BOOTDATA ";
+ outs() << "OPENBSD_BOOTDATA ";
+ break;
+ case ELF::PT_OPENBSD_MUTABLE:
+ outs() << "OPENBSD_MUTABLE ";
break;
case ELF::PT_OPENBSD_RANDOMIZE:
- outs() << " OPENBSD_RANDOMIZE ";
+ outs() << "OPENBSD_RANDOMIZE ";
break;
case ELF::PT_OPENBSD_WXNEEDED:
- outs() << " OPENBSD_WXNEEDED ";
+ outs() << "OPENBSD_WXNEEDED ";
break;
case ELF::PT_PHDR:
outs() << " PHDR ";
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
index cdbecd5..fadc836 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
@@ -78,9 +78,11 @@
static bool ArchiveMemberOffsets;
bool objdump::IndirectSymbols;
bool objdump::DataInCode;
-bool objdump::FunctionStarts;
+FunctionStartsMode objdump::FunctionStartsType =
+ objdump::FunctionStartsMode::None;
bool objdump::LinkOptHints;
bool objdump::InfoPlist;
+bool objdump::ChainedFixups;
bool objdump::DyldInfo;
bool objdump::DylibsUsed;
bool objdump::DylibId;
@@ -93,6 +95,8 @@
static bool ArchAll = false;
static std::string ThumbTripleName;
+static StringRef ordinalName(const object::MachOObjectFile *, int);
+
void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);
ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);
@@ -109,9 +113,18 @@
ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);
IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);
DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);
- FunctionStarts = InputArgs.hasArg(OBJDUMP_function_starts);
+ if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {
+ FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())
+ .Case("addrs", FunctionStartsMode::Addrs)
+ .Case("names", FunctionStartsMode::Names)
+ .Case("both", FunctionStartsMode::Both)
+ .Default(FunctionStartsMode::None);
+ if (FunctionStartsType == FunctionStartsMode::None)
+ invalidArgValue(A);
+ }
LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);
InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);
+ ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);
DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);
DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);
DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);
@@ -242,19 +255,19 @@
case MachO::DICE_KIND_DATA:
if (Length >= 4) {
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 4), outs());
+ dumpBytes(ArrayRef(bytes, 4), outs());
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
Size = 4;
} else if (Length >= 2) {
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 2), outs());
+ dumpBytes(ArrayRef(bytes, 2), outs());
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << Value;
Size = 2;
} else {
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 2), outs());
+ dumpBytes(ArrayRef(bytes, 2), outs());
Value = bytes[0];
outs() << "\t.byte " << Value;
Size = 1;
@@ -266,14 +279,14 @@
break;
case MachO::DICE_KIND_JUMP_TABLE8:
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 1), outs());
+ dumpBytes(ArrayRef(bytes, 1), outs());
Value = bytes[0];
outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
Size = 1;
break;
case MachO::DICE_KIND_JUMP_TABLE16:
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 2), outs());
+ dumpBytes(ArrayRef(bytes, 2), outs());
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << format("%5u", Value & 0xffff)
<< "\t@ KIND_JUMP_TABLE16\n";
@@ -282,7 +295,7 @@
case MachO::DICE_KIND_JUMP_TABLE32:
case MachO::DICE_KIND_ABS_JUMP_TABLE32:
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 4), outs());
+ dumpBytes(ArrayRef(bytes, 4), outs());
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
@@ -1076,12 +1089,39 @@
}
}
+ DenseMap<uint64_t, StringRef> SymbolNames;
+ if (FunctionStartsType == FunctionStartsMode::Names ||
+ FunctionStartsType == FunctionStartsMode::Both) {
+ for (SymbolRef Sym : O->symbols()) {
+ if (Expected<uint64_t> Addr = Sym.getAddress()) {
+ if (Expected<StringRef> Name = Sym.getName()) {
+ SymbolNames[*Addr] = *Name;
+ }
+ }
+ }
+ }
+
for (uint64_t S : FunctionStarts) {
uint64_t Addr = BaseSegmentAddress + S;
- if (O->is64Bit())
- outs() << format("%016" PRIx64, Addr) << "\n";
- else
- outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr)) << "\n";
+ if (FunctionStartsType == FunctionStartsMode::Names) {
+ auto It = SymbolNames.find(Addr);
+ if (It != SymbolNames.end())
+ outs() << It->second << "\n";
+ } else {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, Addr);
+ else
+ outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));
+
+ if (FunctionStartsType == FunctionStartsMode::Both) {
+ auto It = SymbolNames.find(Addr);
+ if (It != SymbolNames.end())
+ outs() << " " << It->second;
+ else
+ outs() << " ?";
+ }
+ outs() << "\n";
+ }
}
}
@@ -1184,18 +1224,209 @@
}
}
-static void printMachOChainedFixups(object::MachOObjectFile *Obj) {
- Error Err = Error::success();
- for (const object::MachOChainedFixupEntry &Entry : Obj->fixupTable(Err)) {
- (void)Entry;
+static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {
+ SmallVector<std::string> Ret;
+ for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
+ Ret.push_back(SLC.segname);
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
+ Ret.push_back(SLC.segname);
+ }
}
- if (Err)
- reportError(std::move(Err), Obj->getFileName());
+ return Ret;
+}
+
+static void
+PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
+ outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
+ outs() << " fixups_version = " << H.fixups_version << '\n';
+ outs() << " starts_offset = " << H.starts_offset << '\n';
+ outs() << " imports_offset = " << H.imports_offset << '\n';
+ outs() << " symbols_offset = " << H.symbols_offset << '\n';
+ outs() << " imports_count = " << H.imports_count << '\n';
+
+ outs() << " imports_format = " << H.imports_format;
+ switch (H.imports_format) {
+ case llvm::MachO::DYLD_CHAINED_IMPORT:
+ outs() << " (DYLD_CHAINED_IMPORT)";
+ break;
+ case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:
+ outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";
+ break;
+ case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:
+ outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";
+ break;
+ }
+ outs() << '\n';
+
+ outs() << " symbols_format = " << H.symbols_format;
+ if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)
+ outs() << " (zlib compressed)";
+ outs() << '\n';
+}
+
+static constexpr std::array<StringRef, 13> PointerFormats{
+ "DYLD_CHAINED_PTR_ARM64E",
+ "DYLD_CHAINED_PTR_64",
+ "DYLD_CHAINED_PTR_32",
+ "DYLD_CHAINED_PTR_32_CACHE",
+ "DYLD_CHAINED_PTR_32_FIRMWARE",
+ "DYLD_CHAINED_PTR_64_OFFSET",
+ "DYLD_CHAINED_PTR_ARM64E_KERNEL",
+ "DYLD_CHAINED_PTR_64_KERNEL_CACHE",
+ "DYLD_CHAINED_PTR_ARM64E_USERLAND",
+ "DYLD_CHAINED_PTR_ARM64E_FIRMWARE",
+ "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",
+ "DYLD_CHAINED_PTR_ARM64E_USERLAND24",
+};
+
+static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,
+ StringRef SegName) {
+ outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName
+ << ")\n";
+ outs() << " size = " << Segment.Header.size << '\n';
+ outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)
+ << '\n';
+
+ outs() << " pointer_format = " << Segment.Header.pointer_format;
+ if ((Segment.Header.pointer_format - 1) <
+ MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)
+ outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";
+ outs() << '\n';
+
+ outs() << " segment_offset = "
+ << format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';
+ outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer
+ << '\n';
+ outs() << " page_count = " << Segment.Header.page_count << '\n';
+ for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {
+ outs() << " page_start[" << Index << "] = " << PageStart;
+ // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)
+ if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)
+ outs() << " (DYLD_CHAINED_PTR_START_NONE)";
+ outs() << '\n';
+ }
+}
+
+static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,
+ int Format, MachOObjectFile *O) {
+ if (Format == MachO::DYLD_CHAINED_IMPORT)
+ outs() << "dyld chained import";
+ else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
+ outs() << "dyld chained import addend";
+ else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
+ outs() << "dyld chained import addend64";
+ // FIXME: otool prints the encoded value as well.
+ outs() << '[' << Idx << "]\n";
+
+ outs() << " lib_ordinal = " << Target.libOrdinal() << " ("
+ << ordinalName(O, Target.libOrdinal()) << ")\n";
+ outs() << " weak_import = " << Target.weakImport() << '\n';
+ outs() << " name_offset = " << Target.nameOffset() << " ("
+ << Target.symbolName() << ")\n";
+ if (Format != MachO::DYLD_CHAINED_IMPORT)
+ outs() << " addend = " << (int64_t)Target.addend() << '\n';
+}
+
+static void PrintChainedFixups(MachOObjectFile *O) {
+ // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
+ // FIXME: Support chained fixups in __TEXT,__chain_starts section too.
+ auto ChainedFixupHeader =
+ unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());
+ if (!ChainedFixupHeader)
+ return;
+
+ PrintChainedFixupsHeader(*ChainedFixupHeader);
+
+ auto [SegCount, Segments] =
+ unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());
+
+ auto SegNames = GetSegmentNames(O);
+
+ size_t StartsIdx = 0;
+ outs() << "chained starts in image\n";
+ outs() << " seg_count = " << SegCount << '\n';
+ for (size_t I = 0; I < SegCount; ++I) {
+ uint64_t SegOffset = 0;
+ if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {
+ SegOffset = Segments[StartsIdx].Offset;
+ ++StartsIdx;
+ }
+
+ outs() << " seg_offset[" << I << "] = " << SegOffset << " ("
+ << SegNames[I] << ")\n";
+ }
+
+ for (const ChainedFixupsSegment &S : Segments)
+ PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);
+
+ auto FixupTargets =
+ unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());
+
+ uint32_t ImportsFormat = ChainedFixupHeader->imports_format;
+ for (auto [Idx, Target] : enumerate(FixupTargets))
+ PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);
}
static void PrintDyldInfo(MachOObjectFile *O) {
- outs() << "dyld information:" << '\n';
- printMachOChainedFixups(O);
+ Error Err = Error::success();
+
+ size_t SegmentWidth = strlen("segment");
+ size_t SectionWidth = strlen("section");
+ size_t AddressWidth = strlen("address");
+ size_t AddendWidth = strlen("addend");
+ size_t DylibWidth = strlen("dylib");
+ const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;
+
+ auto HexLength = [](uint64_t Num) {
+ return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;
+ };
+ for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
+ SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());
+ SectionWidth = std::max(SectionWidth, Entry.sectionName().size());
+ AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);
+ if (Entry.isBind()) {
+ AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);
+ DylibWidth = std::max(DylibWidth, Entry.symbolName().size());
+ }
+ }
+ // Errors will be handled when printing the table.
+ if (Err)
+ consumeError(std::move(Err));
+
+ outs() << "dyld information:\n";
+ outs() << left_justify("segment", SegmentWidth) << ' '
+ << left_justify("section", SectionWidth) << ' '
+ << left_justify("address", AddressWidth) << ' '
+ << left_justify("pointer", PointerWidth) << " type "
+ << left_justify("addend", AddendWidth) << ' '
+ << left_justify("dylib", DylibWidth) << " symbol/vm address\n";
+ for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
+ outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '
+ << left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"
+ << left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '
+ << format_hex(Entry.rawValue(), PointerWidth, true) << ' ';
+ if (Entry.isBind()) {
+ outs() << "bind "
+ << "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)
+ << ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)
+ << ' ' << Entry.symbolName();
+ if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
+ outs() << " (weak import)";
+ outs() << '\n';
+ } else {
+ assert(Entry.isRebase());
+ outs() << "rebase";
+ outs().indent(AddendWidth + DylibWidth + 2);
+ outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';
+ }
+ }
+ if (Err)
+ reportError(std::move(Err), O->getFileName());
+
+ // TODO: Print opcode-based fixups if the object uses those.
}
static void PrintDylibs(MachOObjectFile *O, bool JustId) {
@@ -1916,8 +2147,9 @@
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
- DataInCode || FunctionStarts || LinkOptHints || DyldInfo || DylibsUsed ||
- DylibId || Rpaths || ObjcMetaData || (!FilterSections.empty())) {
+ DataInCode || FunctionStartsType != FunctionStartsMode::None ||
+ LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||
+ Rpaths || ObjcMetaData || (!FilterSections.empty())) {
if (LeadingHeaders) {
outs() << Name;
if (!ArchiveMemberName.empty())
@@ -1972,7 +2204,7 @@
PrintIndirectSymbols(MachOOF, Verbose);
if (DataInCode)
PrintDataInCodeTable(MachOOF, Verbose);
- if (FunctionStarts)
+ if (FunctionStartsType != FunctionStartsMode::None)
PrintFunctionStarts(MachOOF);
if (LinkOptHints)
PrintLinkOptHints(MachOOF);
@@ -1988,6 +2220,8 @@
DumpInfoPlistSectionContents(FileName, MachOOF);
if (DyldInfo)
PrintDyldInfo(MachOOF);
+ if (ChainedFixups)
+ PrintChainedFixups(MachOOF);
if (DylibsUsed)
PrintDylibs(MachOOF, false);
if (DylibId)
@@ -7189,6 +7423,108 @@
CommentsToEmit.clear();
}
+const MachOObjectFile *
+objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,
+ std::unique_ptr<Binary> &DSYMBinary,
+ std::unique_ptr<MemoryBuffer> &DSYMBuf) {
+ const MachOObjectFile *DbgObj = MachOOF;
+ std::string DSYMPath;
+
+ // Auto-detect w/o --dsym.
+ if (DSYMFile.empty()) {
+ sys::fs::file_status DSYMStatus;
+ Twine FilenameDSYM = Filename + ".dSYM";
+ if (!status(FilenameDSYM, DSYMStatus)) {
+ if (sys::fs::is_directory(DSYMStatus)) {
+ SmallString<1024> Path;
+ FilenameDSYM.toVector(Path);
+ sys::path::append(Path, "Contents", "Resources", "DWARF",
+ sys::path::filename(Filename));
+ DSYMPath = std::string(Path);
+ } else if (sys::fs::is_regular_file(DSYMStatus)) {
+ DSYMPath = FilenameDSYM.str();
+ }
+ }
+ }
+
+ if (DSYMPath.empty() && !DSYMFile.empty()) {
+ // If DSYMPath is a .dSYM directory, append the Mach-O file.
+ if (sys::fs::is_directory(DSYMFile) &&
+ sys::path::extension(DSYMFile) == ".dSYM") {
+ SmallString<128> ShortName(sys::path::filename(DSYMFile));
+ sys::path::replace_extension(ShortName, "");
+ SmallString<1024> FullPath(DSYMFile);
+ sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);
+ DSYMPath = FullPath.str();
+ } else {
+ DSYMPath = DSYMFile;
+ }
+ }
+
+ if (!DSYMPath.empty()) {
+ // Load the file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFileOrSTDIN(DSYMPath);
+ if (std::error_code EC = BufOrErr.getError()) {
+ reportError(errorCodeToError(EC), DSYMPath);
+ return nullptr;
+ }
+
+ // We need to keep the file alive, because we're replacing DbgObj with it.
+ DSYMBuf = std::move(BufOrErr.get());
+
+ Expected<std::unique_ptr<Binary>> BinaryOrErr =
+ createBinary(DSYMBuf.get()->getMemBufferRef());
+ if (!BinaryOrErr) {
+ reportError(BinaryOrErr.takeError(), DSYMPath);
+ return nullptr;
+ }
+
+ // We need to keep the Binary alive with the buffer
+ DSYMBinary = std::move(BinaryOrErr.get());
+ if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
+ // this is a Mach-O object file, use it
+ if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
+ DbgObj = MachDSYM;
+ } else {
+ WithColor::error(errs(), "llvm-objdump")
+ << DSYMPath << " is not a Mach-O file type.\n";
+ return nullptr;
+ }
+ } else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {
+ // this is a Universal Binary, find a Mach-O for this architecture
+ uint32_t CPUType, CPUSubType;
+ const char *ArchFlag;
+ if (MachOOF->is64Bit()) {
+ const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
+ CPUType = H_64.cputype;
+ CPUSubType = H_64.cpusubtype;
+ } else {
+ const MachO::mach_header H = MachOOF->getHeader();
+ CPUType = H.cputype;
+ CPUSubType = H.cpusubtype;
+ }
+ Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
+ &ArchFlag);
+ Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
+ UB->getMachOObjectForArch(ArchFlag);
+ if (!MachDSYM) {
+ reportError(MachDSYM.takeError(), DSYMPath);
+ return nullptr;
+ }
+
+ // We need to keep the Binary alive with the buffer
+ DbgObj = &*MachDSYM.get();
+ DSYMBinary = std::move(*MachDSYM);
+ } else {
+ WithColor::error(errs(), "llvm-objdump")
+ << DSYMPath << " is not a Mach-O or Universal file type.\n";
+ return nullptr;
+ }
+ }
+ return DbgObj;
+}
+
static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
StringRef DisSegName, StringRef DisSectName) {
const char *McpuDefault = nullptr;
@@ -7363,90 +7699,15 @@
std::unique_ptr<Binary> DSYMBinary;
std::unique_ptr<MemoryBuffer> DSYMBuf;
if (UseDbg) {
- ObjectFile *DbgObj = MachOOF;
-
- // A separate DSym file path was specified, parse it as a macho file,
+ // If separate DSym file path was specified, parse it as a macho file,
// get the sections and supply it to the section name parsing machinery.
- if (!DSYMFile.empty()) {
- std::string DSYMPath(DSYMFile);
-
- // If DSYMPath is a .dSYM directory, append the Mach-O file.
- if (llvm::sys::fs::is_directory(DSYMPath) &&
- llvm::sys::path::extension(DSYMPath) == ".dSYM") {
- SmallString<128> ShortName(llvm::sys::path::filename(DSYMPath));
- llvm::sys::path::replace_extension(ShortName, "");
- SmallString<1024> FullPath(DSYMPath);
- llvm::sys::path::append(FullPath, "Contents", "Resources", "DWARF",
- ShortName);
- DSYMPath = std::string(FullPath.str());
- }
-
- // Load the file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFileOrSTDIN(DSYMPath);
- if (std::error_code EC = BufOrErr.getError()) {
- reportError(errorCodeToError(EC), DSYMPath);
- return;
- }
-
- // We need to keep the file alive, because we're replacing DbgObj with it.
- DSYMBuf = std::move(BufOrErr.get());
-
- Expected<std::unique_ptr<Binary>> BinaryOrErr =
- createBinary(DSYMBuf.get()->getMemBufferRef());
- if (!BinaryOrErr) {
- reportError(BinaryOrErr.takeError(), DSYMPath);
- return;
- }
-
- // We need to keep the Binary alive with the buffer
- DSYMBinary = std::move(BinaryOrErr.get());
- if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
- // this is a Mach-O object file, use it
- if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
- DbgObj = MachDSYM;
- }
- else {
- WithColor::error(errs(), "llvm-objdump")
- << DSYMPath << " is not a Mach-O file type.\n";
- return;
- }
- }
- else if (auto UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())){
- // this is a Universal Binary, find a Mach-O for this architecture
- uint32_t CPUType, CPUSubType;
- const char *ArchFlag;
- if (MachOOF->is64Bit()) {
- const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
- CPUType = H_64.cputype;
- CPUSubType = H_64.cpusubtype;
- } else {
- const MachO::mach_header H = MachOOF->getHeader();
- CPUType = H.cputype;
- CPUSubType = H.cpusubtype;
- }
- Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
- &ArchFlag);
- Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
- UB->getMachOObjectForArch(ArchFlag);
- if (!MachDSYM) {
- reportError(MachDSYM.takeError(), DSYMPath);
- return;
- }
-
- // We need to keep the Binary alive with the buffer
- DbgObj = &*MachDSYM.get();
- DSYMBinary = std::move(*MachDSYM);
- }
- else {
- WithColor::error(errs(), "llvm-objdump")
- << DSYMPath << " is not a Mach-O or Universal file type.\n";
- return;
- }
+ if (const ObjectFile *DbgObj =
+ getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf)) {
+ // Setup the DIContext
+ diContext = DWARFContext::create(*DbgObj);
+ } else {
+ return;
}
-
- // Setup the DIContext
- diContext = DWARFContext::create(*DbgObj);
}
if (FilterSections.empty())
@@ -7655,7 +7916,7 @@
Annotations);
if (gotInst) {
if (ShowRawInsn || Arch == Triple::arm) {
- dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs());
+ dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());
}
formatted_raw_ostream FormattedOS(outs());
StringRef AnnotationsStr = Annotations.str();
@@ -7736,7 +7997,7 @@
}
if (ShowRawInsn || Arch == Triple::arm) {
outs() << "\t";
- dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());
+ dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());
}
StringRef AnnotationsStr = Annotations.str();
IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());
@@ -8445,6 +8706,9 @@
case MachO::MH_KEXT_BUNDLE:
outs() << " KEXTBUNDLE";
break;
+ case MachO::MH_FILESET:
+ outs() << " FILESET";
+ break;
default:
outs() << format(" %10u", filetype);
break;
@@ -8657,6 +8921,12 @@
outs() << " PROTECTED_VERSION_1";
flags &= ~MachO::SG_PROTECTED_VERSION_1;
}
+ if (flags & MachO::SG_READ_ONLY) {
+ // Apple's otool prints the SG_ prefix for this flag, but not for the
+ // others.
+ outs() << " SG_READ_ONLY";
+ flags &= ~MachO::SG_READ_ONLY;
+ }
if (flags)
outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";
else
@@ -8754,6 +9024,8 @@
outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
+ else if (section_type == MachO::S_INIT_FUNC_OFFSETS)
+ outs() << " S_INIT_FUNC_OFFSETS\n";
else
outs() << format("0x%08" PRIx32, section_type) << "\n";
outs() << "attributes";
@@ -10381,6 +10653,8 @@
return "main-executable";
case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
return "flat-namespace";
+ case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
+ return "weak";
default:
if (Ordinal > 0) {
std::error_code EC =
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/MachODump.h b/src/llvm-project/llvm/tools/llvm-objdump/MachODump.h
index 12783e1..d9d3a70 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/MachODump.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/MachODump.h
@@ -16,12 +16,14 @@
class Error;
class StringRef;
+class MemoryBuffer;
namespace object {
class MachOObjectFile;
class MachOUniversalBinary;
class ObjectFile;
class RelocationRef;
+class Binary;
} // namespace object
namespace opt {
@@ -32,17 +34,20 @@
void parseMachOOptions(const llvm::opt::InputArgList &InputArgs);
+enum class FunctionStartsMode { Addrs, Names, Both, None };
+
// MachO specific options
extern bool Bind;
extern bool DataInCode;
extern std::string DisSymName;
+extern bool ChainedFixups;
extern bool DyldInfo;
extern bool DylibId;
extern bool DylibsUsed;
extern bool ExportsTrie;
extern bool FirstPrivateHeader;
extern bool FullLeadingAddr;
-extern bool FunctionStarts;
+extern FunctionStartsMode FunctionStartsType;
extern bool IndirectSymbols;
extern bool InfoPlist;
extern bool LazyBind;
@@ -60,6 +65,11 @@
const object::RelocationRef &RelRef,
llvm::SmallVectorImpl<char> &Result);
+const object::MachOObjectFile *
+getMachODSymObject(const object::MachOObjectFile *O, StringRef Filename,
+ std::unique_ptr<object::Binary> &DSYMBinary,
+ std::unique_ptr<MemoryBuffer> &DSYMBuf);
+
void parseInputMachO(StringRef Filename);
void parseInputMachO(object::MachOUniversalBinary *UB);
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td b/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td
index 00d7d8c..c6627c7 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td
+++ b/src/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td
@@ -1,5 +1,10 @@
include "llvm/Option/OptParser.td"
+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 : Separate<["--"], name>;
def NAME #_eq : Joined<["--"], name #"=">,
@@ -33,12 +38,22 @@
def archive_headers : Flag<["--"], "archive-headers">,
HelpText<"Display archive header information">;
+defm build_id :
+ Eq<"build-id", "Build ID to look up. Once found, added as an input file">,
+ MetaVarName<"<hex>">;
+
def : Flag<["-"], "a">, Alias<archive_headers>,
HelpText<"Alias for --archive-headers">;
def demangle : Flag<["--"], "demangle">, HelpText<"Demangle symbol names">;
def : Flag<["-"], "C">, Alias<demangle>, HelpText<"Alias for --demangle">;
+defm debug_file_directory :
+ Eq<"debug-file-directory", "Path to directory where to look for debug files">,
+ MetaVarName<"<dir>">;
+
+defm debuginfod : B<"debuginfod", "Use debuginfod to find debug files", "Don't use debuginfod to find debug files">;
+
def disassemble : Flag<["--"], "disassemble">,
HelpText<"Disassemble all executable sections found in the input files">;
def : Flag<["-"], "d">, Alias<disassemble>, HelpText<"Alias for --disassemble">;
@@ -118,7 +133,9 @@
"do not print the instruction bytes.">;
def no_leading_addr : Flag<["--"], "no-leading-addr">,
- HelpText<"When disassembling, do not print leading addresses">;
+ HelpText<"When disassembling, do not print leading addresses for instructions or inline relocations">;
+def : Flag<["--"], "no-addresses">, Alias<no_leading_addr>,
+ HelpText<"Alias for --no-leading-addr">;
def raw_clang_ast : Flag<["--"], "raw-clang-ast">,
HelpText<"Dump the raw binary contents of the clang AST section">;
@@ -128,10 +145,10 @@
def : Flag<["-"], "r">, Alias<reloc>, HelpText<"Alias for --reloc">;
def print_imm_hex : Flag<["--"], "print-imm-hex">,
- HelpText<"Use hex format for immediate values">;
+ HelpText<"Use hex format for immediate values (default)">;
def no_print_imm_hex : Flag<["--"], "no-print-imm-hex">,
- HelpText<"Do not use hex format for immediate values (default)">;
+ HelpText<"Do not use hex format for immediate values">;
def : Flag<["--"], "print-imm-hex=false">, Alias<no_print_imm_hex>;
def private_headers : Flag<["--"], "private-headers">,
@@ -153,6 +170,10 @@
def : Flag<["-"], "h">, Alias<section_headers>,
HelpText<"Alias for --section-headers">;
+def show_all_symbols : Flag<["--"], "show-all-symbols">,
+ HelpText<"Show all symbols during disassembly, even if multiple "
+ "symbols are defined at the same location">;
+
def show_lma : Flag<["--"], "show-lma">,
HelpText<"Display LMA column when dumping ELF section headers">;
@@ -284,11 +305,15 @@
HelpText<"Print the data in code table for Mach-O objects (requires --macho)">,
Group<grp_mach_o>;
-def function_starts : Flag<["--"], "function-starts">,
- HelpText<"Print the function starts table for "
- "Mach-O objects (requires --macho)">,
+def function_starts_EQ : Joined<["--"], "function-starts=">,
+ HelpText<"Print the function starts table for Mach-O objects. "
+ "Options: addrs (default), names, both (requires --macho)">,
+ Values<"addrs,names,both">,
Group<grp_mach_o>;
+def : Flag<["--"], "function-starts">, Alias<function_starts_EQ>,
+ AliasArgs<["addrs"]>, Group<grp_mach_o>;
+
def link_opt_hints : Flag<["--"], "link-opt-hints">,
HelpText<"Print the linker optimization hints for "
"Mach-O objects (requires --macho)">,
@@ -299,11 +324,15 @@
"Mach-O objects (requires --macho)">,
Group<grp_mach_o>;
-def dyld_info : Flag<["--"], "dyld_info">,
- HelpText<"Print bind and rebase information used by dyld to resolve "
- "external references in a final linked binary "
- "(requires --macho)">,
- Group<grp_mach_o>;
+def chained_fixups : Flag<["--"], "chained-fixups">,
+ HelpText<"Print chained fixup information (requires --macho)">,
+ Group<grp_mach_o>;
+
+def dyld_info : Flag<["--"], "dyld-info">,
+ HelpText<"Print bind and rebase information used by dyld to resolve "
+ "external references in a final linked binary "
+ "(requires --macho)">,
+ Group<grp_mach_o>;
def dylibs_used : Flag<["--"], "dylibs-used">,
HelpText<"Print the shared libraries used for linked "
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/OffloadDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/OffloadDump.cpp
index 46334c2..4ac6b99 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/OffloadDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/OffloadDump.cpp
@@ -10,6 +10,7 @@
/// This file implements the offloading-specific dumper for llvm-objdump.
///
//===----------------------------------------------------------------------===//
+
#include "OffloadDump.h"
#include "llvm-objdump.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -46,67 +47,34 @@
<< getOffloadKindName(OB.getOffloadKind()) << "\n";
}
-static Error visitAllBinaries(const OffloadBinary &OB) {
- uint64_t Offset = 0;
- uint64_t Index = 0;
- while (Offset < OB.getMemoryBufferRef().getBufferSize()) {
- MemoryBufferRef Buffer =
- MemoryBufferRef(OB.getData().drop_front(Offset), OB.getFileName());
- auto BinaryOrErr = OffloadBinary::create(Buffer);
- if (!BinaryOrErr)
- return BinaryOrErr.takeError();
-
- OffloadBinary &Binary = **BinaryOrErr;
- printBinary(Binary, Index++);
-
- Offset += Binary.getSize();
- }
- return Error::success();
-}
-
/// Print the embedded offloading contents of an ObjectFile \p O.
void llvm::dumpOffloadBinary(const ObjectFile &O) {
- if (!O.isELF()) {
- reportWarning("--offloading is currently only supported for ELF targets",
- O.getFileName());
+ if (!O.isELF() && !O.isCOFF()) {
+ reportWarning(
+ "--offloading is currently only supported for COFF and ELF targets",
+ O.getFileName());
return;
}
- for (ELFSectionRef Sec : O.sections()) {
- if (Sec.getType() != ELF::SHT_LLVM_OFFLOADING)
- continue;
+ SmallVector<OffloadFile> Binaries;
+ if (Error Err = extractOffloadBinaries(O.getMemoryBufferRef(), Binaries))
+ reportError(O.getFileName(), "while extracting offloading files: " +
+ toString(std::move(Err)));
- Expected<StringRef> Contents = Sec.getContents();
- if (!Contents)
- reportError(Contents.takeError(), O.getFileName());
-
- std::unique_ptr<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBuffer(*Contents, O.getFileName(), false);
- if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
- Buffer->getBufferStart()))
- Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(),
- Buffer->getBufferIdentifier());
- auto BinaryOrErr = OffloadBinary::create(*Buffer);
- if (!BinaryOrErr)
- reportError(O.getFileName(), "while extracting offloading files: " +
- toString(BinaryOrErr.takeError()));
- OffloadBinary &Binary = **BinaryOrErr;
-
- // Print out all the binaries that are contained in this buffer. If we fail
- // to parse a binary before reaching the end of the buffer emit a warning.
- if (Error Err = visitAllBinaries(Binary))
- reportWarning("while parsing offloading files: " +
- toString(std::move(Err)),
- O.getFileName());
- }
+ // Print out all the binaries that are contained in this buffer.
+ for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
+ printBinary(*Binaries[I].getBinary(), I);
}
/// Print the contents of an offload binary file \p OB. This may contain
/// multiple binaries stored in the same buffer.
void llvm::dumpOffloadSections(const OffloadBinary &OB) {
- // Print out all the binaries that are contained at this buffer. If we fail to
- // parse a binary before reaching the end of the buffer emit a warning.
- if (Error Err = visitAllBinaries(OB))
- reportWarning("while parsing offloading files: " + toString(std::move(Err)),
- OB.getFileName());
+ SmallVector<OffloadFile> Binaries;
+ if (Error Err = extractOffloadBinaries(OB.getMemoryBufferRef(), Binaries))
+ reportError(OB.getFileName(), "while extracting offloading files: " +
+ toString(std::move(Err)));
+
+ // Print out all the binaries that are contained in this buffer.
+ for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
+ printBinary(*Binaries[I].getBinary(), I);
}
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/OtoolOpts.td b/src/llvm-project/llvm/tools/llvm-objdump/OtoolOpts.td
index e8bef28..dc7a5b4 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/OtoolOpts.td
+++ b/src/llvm-project/llvm/tools/llvm-objdump/OtoolOpts.td
@@ -37,13 +37,16 @@
def x : Flag<["-"], "x">, HelpText<"print all text sections">;
def X : Flag<["-"], "X">, HelpText<"omit leading addresses or headers">;
+def chained_fixups : Flag<["-"], "chained_fixups">,
+ HelpText<"print chained fixup information">;
+def dyld_info : Flag<["-"], "dyld_info">,
+ HelpText<"print bind and rebase information">;
+
// Not (yet?) implemented:
// def a : Flag<["-"], "a">, HelpText<"print archive header">;
// -c print argument strings of a core file
// -m don't use archive(member) syntax
-// -dyld_info
// -dyld_opcodes
-// -chained_fixups
// -addr_slide=arg
// -function_offsets
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp b/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp
index c8ea6b5..6736cbc 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp
@@ -31,7 +31,7 @@
}
bool LiveVariable::liveAtAddress(object::SectionedAddress Addr) {
- if (LocExpr.Range == None)
+ if (LocExpr.Range == std::nullopt)
return false;
return LocExpr.Range->SectionIndex == Addr.SectionIndex &&
LocExpr.Range->LowPC <= Addr.Address &&
@@ -42,7 +42,17 @@
DataExtractor Data({LocExpr.Expr.data(), LocExpr.Expr.size()},
Unit->getContext().isLittleEndian(), 0);
DWARFExpression Expression(Data, Unit->getAddressByteSize());
- Expression.printCompact(OS, MRI);
+
+ auto GetRegName = [&MRI, &OS](uint64_t DwarfRegNum, bool IsEH) -> StringRef {
+ if (std::optional<unsigned> LLVMRegNum =
+ MRI.getLLVMRegNum(DwarfRegNum, IsEH))
+ if (const char *RegName = MRI.getName(*LLVMRegNum))
+ return StringRef(RegName);
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return {};
+ };
+
+ Expression.printCompact(OS, GetRegName);
}
void LiveVariablePrinter::addVariable(DWARFDie FuncDie, DWARFDie VarDie) {
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h b/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h
index 29ef19c..6209bb0 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h
@@ -13,6 +13,7 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/FormattedStream.h"
#include <unordered_map>
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
index dd1570e1..7171e2e 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
@@ -43,31 +43,31 @@
return Error::success();
}
-Optional<XCOFF::StorageMappingClass>
+std::optional<XCOFF::StorageMappingClass>
objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,
const SymbolRef &Sym) {
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
if (!SymRef.isCsectSymbol())
- return None;
+ return std::nullopt;
auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
if (!CsectAuxEntOrErr)
- return None;
+ return std::nullopt;
return CsectAuxEntOrErr.get().getStorageMappingClass();
}
-Optional<object::SymbolRef>
+std::optional<object::SymbolRef>
objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,
const SymbolRef &Sym) {
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
if (!SymRef.isCsectSymbol())
- return None;
+ return std::nullopt;
Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
- return None;
+ return std::nullopt;
uint32_t Idx =
static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
DataRefImpl DRI;
@@ -94,9 +94,9 @@
std::string Result;
// Dummy symbols have no symbol index.
if (SymbolInfo.XCOFFSymInfo.Index)
- Result = ("(idx: " + Twine(SymbolInfo.XCOFFSymInfo.Index.value()) + ") " +
- SymbolName)
- .str();
+ Result =
+ ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)
+ .str();
else
Result.append(SymbolName.begin(), SymbolName.end());
diff --git a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h
index 4616059..35d1c0f 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h
@@ -16,11 +16,11 @@
struct SymbolInfoTy;
namespace objdump {
-Optional<XCOFF::StorageMappingClass>
+std::optional<XCOFF::StorageMappingClass>
getXCOFFSymbolCsectSMC(const object::XCOFFObjectFile &Obj,
const object::SymbolRef &Sym);
-Optional<object::SymbolRef>
+std::optional<object::SymbolRef>
getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile &Obj,
const object::SymbolRef &Sym);
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 fd83dc1..9979a26 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -25,7 +25,6 @@
#include "WasmDump.h"
#include "XCOFFDump.h"
#include "llvm/ADT/IndexedMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallSet.h"
@@ -36,6 +35,9 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/Debuginfod/BuildIDFetcher.h"
+#include "llvm/Debuginfod/Debuginfod.h"
+#include "llvm/Debuginfod/HTTPClient.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -51,6 +53,7 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/BuildID.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -82,6 +85,7 @@
#include <algorithm>
#include <cctype>
#include <cstring>
+#include <optional>
#include <system_error>
#include <unordered_map>
#include <utility>
@@ -93,18 +97,19 @@
namespace {
-class CommonOptTable : public opt::OptTable {
+class CommonOptTable : public opt::GenericOptTable {
public:
CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage,
const char *Description)
- : OptTable(OptionInfos), Usage(Usage), Description(Description) {
+ : opt::GenericOptTable(OptionInfos), Usage(Usage),
+ Description(Description) {
setGroupedShortOptions(true);
}
void printHelp(StringRef Argv0, bool ShowHidden = false) const {
Argv0 = sys::path::filename(Argv0);
- opt::OptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), Description,
- ShowHidden, ShowHidden);
+ opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(),
+ Description, ShowHidden, ShowHidden);
// TODO Replace this with OptTable API once it adds extrahelp support.
outs() << "\nPass @FILE as argument to read options from FILE.\n";
}
@@ -115,28 +120,31 @@
};
// ObjdumpOptID is in ObjdumpOptID.h
-
-#define PREFIX(NAME, VALUE) const char *const OBJDUMP_##NAME[] = VALUE;
+namespace objdump_opt {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "ObjdumpOpts.inc"
#undef PREFIX
static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {
-#define OBJDUMP_nullptr nullptr
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {OBJDUMP_##PREFIX, NAME, HELPTEXT, \
- METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OBJDUMP_##GROUP, \
- OBJDUMP_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OBJDUMP_##GROUP, \
+ OBJDUMP_##ALIAS, ALIASARGS, VALUES},
#include "ObjdumpOpts.inc"
#undef OPTION
-#undef OBJDUMP_nullptr
};
+} // namespace objdump_opt
class ObjdumpOptTable : public CommonOptTable {
public:
ObjdumpOptTable()
- : CommonOptTable(ObjdumpInfoTable, " [options] <input object files>",
+ : CommonOptTable(objdump_opt::ObjdumpInfoTable,
+ " [options] <input object files>",
"llvm object file dumper") {}
};
@@ -149,27 +157,30 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const OTOOL_##NAME[] = VALUE;
+namespace otool {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "OtoolOpts.inc"
#undef PREFIX
static constexpr opt::OptTable::Info OtoolInfoTable[] = {
-#define OTOOL_nullptr nullptr
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {OTOOL_##PREFIX, NAME, HELPTEXT, \
- METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OTOOL_##GROUP, \
- OTOOL_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OTOOL_##GROUP, \
+ OTOOL_##ALIAS, ALIASARGS, VALUES},
#include "OtoolOpts.inc"
#undef OPTION
-#undef OTOOL_nullptr
};
+} // namespace otool
class OtoolOptTable : public CommonOptTable {
public:
OtoolOptTable()
- : CommonOptTable(OtoolInfoTable, " [option...] [file...]",
+ : CommonOptTable(otool::OtoolInfoTable, " [option...] [file...]",
"Mach-O object file displaying tool") {}
};
@@ -207,6 +218,7 @@
bool objdump::PrivateHeaders;
std::vector<std::string> objdump::FilterSections;
bool objdump::SectionHeaders;
+static bool ShowAllSymbols;
static bool ShowLMA;
bool objdump::PrintSource;
@@ -232,6 +244,9 @@
StringSet<> objdump::FoundSectionSet;
static StringRef ToolName;
+std::unique_ptr<BuildIDFetcher> BIDFetcher;
+ExitOnError ExitOnErr;
+
namespace {
struct FilterResult {
// True if the section should not be skipped.
@@ -454,16 +469,24 @@
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) {
- StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": ";
+ StringRef Fmt = Is64Bits ? "%016" PRIx64 ": " : "%08" PRIx64 ": ";
SmallString<16> Name;
SmallString<32> Val;
Rel.getTypeName(Name);
if (Error E = getRelocationValueString(Rel, Val))
reportError(std::move(E), FileName);
- OS << format(Fmt.data(), Address) << Name << "\t" << Val;
+ OS << (Is64Bits || !LeadingAddr ? "\t\t" : "\t\t\t");
+ if (LeadingAddr)
+ OS << format(Fmt.data(), Address);
+ OS << Name << "\t" << Val;
}
static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI,
@@ -631,10 +654,10 @@
if (Bytes.size() >= 4) {
// D should be casted to uint32_t here as it is passed by format to
// snprintf as vararg.
- for (uint32_t D : makeArrayRef(
- reinterpret_cast<const support::little32_t *>(Bytes.data()),
- Bytes.size() / 4))
- OS << format(" %08" PRIX32, D);
+ for (uint32_t D :
+ ArrayRef(reinterpret_cast<const support::little32_t *>(Bytes.data()),
+ Bytes.size() / 4))
+ OS << format(" %08" PRIX32, D);
} else {
for (unsigned char B : Bytes)
OS << format(" %02" PRIX8, B);
@@ -690,14 +713,14 @@
OS << ' '
<< format_hex_no_prefix(
llvm::support::endian::read<uint16_t>(
- Bytes.data() + Pos, llvm::support::little),
+ Bytes.data() + Pos, InstructionEndianness),
4);
} else {
for (; Pos + 4 <= End; Pos += 4)
OS << ' '
<< format_hex_no_prefix(
llvm::support::endian::read<uint32_t>(
- Bytes.data() + Pos, llvm::support::little),
+ Bytes.data() + Pos, InstructionEndianness),
8);
}
if (Pos < End) {
@@ -713,6 +736,13 @@
} else
OS << "\t<unknown>";
}
+
+ void setInstructionEndianness(llvm::support::endianness Endianness) {
+ InstructionEndianness = Endianness;
+ }
+
+private:
+ llvm::support::endianness InstructionEndianness = llvm::support::little;
};
ARMPrettyPrinter ARMPrettyPrinterInst;
@@ -844,19 +874,19 @@
llvm_unreachable("Unsupported binary format");
}
-static Optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) {
+static std::optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) {
for (auto SecI : Obj.sections()) {
const WasmSection &Section = Obj.getWasmSection(SecI);
if (Section.Type == wasm::WASM_SEC_CODE)
return SecI;
}
- return None;
+ return std::nullopt;
}
static void
addMissingWasmCodeSymbols(const WasmObjectFile &Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
- Optional<SectionRef> Section = getWasmCodeSection(Obj);
+ std::optional<SectionRef> Section = getWasmCodeSection(Obj);
if (!Section)
return;
SectionSymbolsTy &Symbols = AllSymbols[*Section];
@@ -884,7 +914,7 @@
static void addPltEntries(const ObjectFile &Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
StringSaver &Saver) {
- Optional<SectionRef> Plt = None;
+ std::optional<SectionRef> Plt;
for (const SectionRef &Section : Obj.sections()) {
Expected<StringRef> SecNameOrErr = Section.getName();
if (!SecNameOrErr) {
@@ -1065,7 +1095,7 @@
DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl();
const uint32_t SymbolIndex = XCOFFObj.getSymbolIndex(SymbolDRI.p);
- Optional<XCOFF::StorageMappingClass> Smc =
+ std::optional<XCOFF::StorageMappingClass> Smc =
getXCOFFSymbolCsectSMC(XCOFFObj, Symbol);
return SymbolInfoTy(Addr, Name, Smc, SymbolIndex,
isLabel(XCOFFObj, Symbol));
@@ -1082,7 +1112,7 @@
const uint64_t Addr, StringRef &Name,
uint8_t Type) {
if (Obj.isXCOFF() && SymbolDescription)
- return SymbolInfoTy(Addr, Name, None, None, false);
+ return SymbolInfoTy(Addr, Name, std::nullopt, std::nullopt, false);
else
return SymbolInfoTy(Addr, Name, Type);
}
@@ -1172,8 +1202,9 @@
for (size_t Index = 0; Index != Bytes.size();) {
MCInst Inst;
uint64_t Size;
- ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr);
- DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls());
+ ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index);
+ const uint64_t ThisAddr = SectionAddr + Index;
+ DisAsm->getInstruction(Inst, Size, ThisBytes, ThisAddr, nulls());
if (Size == 0)
Size = std::min<uint64_t>(ThisBytes.size(),
DisAsm->suggestBytesToSkip(ThisBytes, Index));
@@ -1250,8 +1281,27 @@
llvm_unreachable("Unsupported binary format");
}
+// Tries to fetch a more complete version of the given object file using its
+// Build ID. Returns std::nullopt if nothing was found.
+static std::optional<OwningBinary<Binary>>
+fetchBinaryByBuildID(const ObjectFile &Obj) {
+ std::optional<object::BuildIDRef> BuildID = getBuildID(&Obj);
+ if (!BuildID)
+ return std::nullopt;
+ std::optional<std::string> Path = BIDFetcher->fetch(*BuildID);
+ if (!Path)
+ return std::nullopt;
+ Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path);
+ if (!DebugBinary) {
+ reportWarning(toString(DebugBinary.takeError()), *Path);
+ return std::nullopt;
+ }
+ return std::move(*DebugBinary);
+}
+
static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
- MCContext &Ctx, MCDisassembler *PrimaryDisAsm,
+ const ObjectFile &DbgObj, MCContext &Ctx,
+ MCDisassembler *PrimaryDisAsm,
MCDisassembler *SecondaryDisAsm,
const MCInstrAnalysis *MIA, MCInstPrinter *IP,
const MCSubtargetInfo *PrimarySTI,
@@ -1376,7 +1426,7 @@
LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI);
if (DbgVariables != DVDisabled) {
- DICtx = DWARFContext::create(Obj);
+ DICtx = DWARFContext::create(DbgObj);
for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units())
LVP.addCompileUnit(CU->getUnitDIE(false));
}
@@ -1384,13 +1434,13 @@
LLVM_DEBUG(LVP.dump());
std::unordered_map<uint64_t, BBAddrMap> AddrToBBAddrMap;
- auto ReadBBAddrMap = [&](Optional<unsigned> SectionIndex = None) {
+ auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex =
+ std::nullopt) {
AddrToBBAddrMap.clear();
if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {
auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex);
if (!BBAddrMapsOrErr)
- reportWarning(toString(BBAddrMapsOrErr.takeError()),
- Obj.getFileName());
+ reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName());
for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr)
AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr,
std::move(FunctionBBAddrMap));
@@ -1474,28 +1524,118 @@
std::vector<RelocationRef> Rels = RelocMap[Section];
std::vector<RelocationRef>::const_iterator RelCur = Rels.begin();
std::vector<RelocationRef>::const_iterator RelEnd = Rels.end();
- // Disassemble symbol by symbol.
- for (unsigned SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
- std::string SymbolName = Symbols[SI].Name.str();
- if (Demangle)
- SymbolName = demangle(SymbolName);
- // Skip if --disassemble-symbols is not empty and the symbol is not in
- // the list.
- if (!DisasmSymbolSet.empty() && !DisasmSymbolSet.count(SymbolName))
- continue;
-
+ // Loop over each chunk of code between two points where at least
+ // one symbol is defined.
+ for (size_t SI = 0, SE = Symbols.size(); SI != SE;) {
+ // Advance SI past all the symbols starting at the same address,
+ // and make an ArrayRef of them.
+ unsigned FirstSI = SI;
uint64_t Start = Symbols[SI].Addr;
+ ArrayRef<SymbolInfoTy> SymbolsHere;
+ while (SI != SE && Symbols[SI].Addr == Start)
+ ++SI;
+ SymbolsHere = ArrayRef<SymbolInfoTy>(&Symbols[FirstSI], SI - FirstSI);
+
+ // Get the demangled names of all those symbols. We end up with a vector
+ // of StringRef that holds the names we're going to use, and a vector of
+ // std::string that stores the new strings returned by demangle(), if
+ // any. If we don't call demangle() then that vector can stay empty.
+ std::vector<StringRef> SymNamesHere;
+ std::vector<std::string> DemangledSymNamesHere;
+ if (Demangle) {
+ // Fetch the demangled names and store them locally.
+ for (const SymbolInfoTy &Symbol : SymbolsHere)
+ DemangledSymNamesHere.push_back(demangle(Symbol.Name.str()));
+ // Now we've finished modifying that vector, it's safe to make
+ // a vector of StringRefs pointing into it.
+ SymNamesHere.insert(SymNamesHere.begin(), DemangledSymNamesHere.begin(),
+ DemangledSymNamesHere.end());
+ } else {
+ for (const SymbolInfoTy &Symbol : SymbolsHere)
+ SymNamesHere.push_back(Symbol.Name);
+ }
+
+ // Distinguish ELF data from code symbols, which will be used later on to
+ // decide whether to 'disassemble' this chunk as a data declaration via
+ // dumpELFData(), or whether to treat it as code.
+ //
+ // If data _and_ code symbols are defined at the same address, the code
+ // takes priority, on the grounds that disassembling code is our main
+ // purpose here, and it would be a worse failure to _not_ interpret
+ // something that _was_ meaningful as code than vice versa.
+ //
+ // Any ELF symbol type that is not clearly data will be regarded as code.
+ // In particular, one of the uses of STT_NOTYPE is for branch targets
+ // 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
+ // 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;
+ size_t DisplaySymIndex = SymbolsHere.size() - 1;
+ if (Obj.isELF() && !DisassembleAll && Section.isText()) {
+ DisassembleAsData = 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;
+ DisplaySymIndex = i;
+ }
+ }
+ }
+
+ // Decide which symbol(s) from this collection we're going to print.
+ std::vector<bool> SymsToPrint(SymbolsHere.size(), false);
+ // If the user has given the --disassemble-symbols option, then we must
+ // display every symbol in that set, and no others.
+ if (!DisasmSymbolSet.empty()) {
+ bool FoundAny = false;
+ for (size_t i = 0; i < SymbolsHere.size(); ++i) {
+ if (DisasmSymbolSet.count(SymNamesHere[i])) {
+ SymsToPrint[i] = true;
+ FoundAny = true;
+ }
+ }
+
+ // And if none of the symbols here is one that the user asked for, skip
+ // disassembling this entire chunk of code.
+ if (!FoundAny)
+ continue;
+ } else {
+ // 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.
+ SymsToPrint[DisplaySymIndex] = true;
+ }
+
+ // Now that we know we're disassembling this section, override the choice
+ // of which symbols to display by printing _all_ of them at this address
+ // if the user asked for all symbols.
+ //
+ // That way, '--show-all-symbols --disassemble-symbol=foo' will print
+ // only the chunk of code headed by 'foo', but also show any other
+ // symbols defined at that address, such as aliases for 'foo', or the ARM
+ // mapping symbol preceding its code.
+ if (ShowAllSymbols) {
+ for (size_t i = 0; i < SymbolsHere.size(); ++i)
+ SymsToPrint[i] = true;
+ }
+
if (Start < SectionAddr || StopAddress <= Start)
continue;
- else
- FoundDisasmSymbolSet.insert(SymbolName);
+
+ for (size_t i = 0; i < SymbolsHere.size(); ++i)
+ FoundDisasmSymbolSet.insert(SymNamesHere[i]);
// The end is the section end, the beginning of the next symbol, or
// --stop-address.
uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress);
- if (SI + 1 < SE)
- End = std::min(End, Symbols[SI + 1].Addr);
+ if (SI < SE)
+ End = std::min(End, Symbols[SI].Addr);
if (Start >= End || End <= StartAddress)
continue;
Start -= SectionAddr;
@@ -1510,13 +1650,22 @@
}
outs() << '\n';
- if (LeadingAddr)
- outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
- SectionAddr + Start + VMAAdjustment);
- if (Obj.isXCOFF() && SymbolDescription) {
- outs() << getXCOFFSymbolDescription(Symbols[SI], SymbolName) << ":\n";
- } else
- outs() << '<' << SymbolName << ">:\n";
+
+ for (size_t i = 0; i < SymbolsHere.size(); ++i) {
+ if (!SymsToPrint[i])
+ continue;
+
+ const SymbolInfoTy &Symbol = SymbolsHere[i];
+ const StringRef SymbolName = SymNamesHere[i];
+
+ if (LeadingAddr)
+ outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
+ SectionAddr + Start + VMAAdjustment);
+ if (Obj.isXCOFF() && SymbolDescription) {
+ outs() << getXCOFFSymbolDescription(Symbol, SymbolName) << ":\n";
+ } else
+ outs() << '<' << SymbolName << ">:\n";
+ }
// Don't print raw contents of a virtual section. A virtual section
// doesn't have any contents in the file.
@@ -1525,57 +1674,67 @@
continue;
}
- auto Status = DisAsm->onSymbolStart(Symbols[SI], Size,
- Bytes.slice(Start, End - Start),
- SectionAddr + Start, CommentStream);
- // To have round trippable disassembly, we fall back to decoding the
- // remaining bytes as instructions.
+ // See if any of the symbols defined at this location triggers target-
+ // specific disassembly behavior, e.g. of special descriptors or function
+ // prelude information.
//
- // If there is a failure, we disassemble the failed region as bytes before
- // falling back. The target is expected to print nothing in this case.
- //
- // If there is Success or SoftFail i.e no 'real' failure, we go ahead by
- // Size bytes before falling back.
- // So if the entire symbol is 'eaten' by the target:
- // Start += Size // Now Start = End and we will never decode as
- // // instructions
- //
- // Right now, most targets return None i.e ignore to treat a symbol
- // separately. But WebAssembly decodes preludes for some symbols.
- //
- if (Status) {
- if (Status.value() == MCDisassembler::Fail) {
- outs() << "// Error in decoding " << SymbolName
+ // We stop this loop at the first symbol that triggers some kind of
+ // interesting behavior (if any), on the assumption that if two symbols
+ // defined at the same address trigger two conflicting symbol handlers,
+ // the object file is probably confused anyway, and it would make even
+ // less sense to present the output of _both_ handlers, because that
+ // would describe the same data twice.
+ 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);
+
+ if (!Status) {
+ // If onSymbolStart returns std::nullopt, that means it didn't trigger
+ // any interesting handling for this symbol. Try the other symbols
+ // defined at this address.
+ continue;
+ }
+
+ if (*Status == MCDisassembler::Fail) {
+ // If onSymbolStart returns Fail, that means it identified some kind
+ // of special data at this address, but wasn't able to disassemble it
+ // meaningfully. So we fall back to disassembling the failed region
+ // as bytes, assuming that the target detected the failure before
+ // printing anything.
+ //
+ // Return values Success or SoftFail (i.e no 'real' failure) are
+ // expected to mean that the target has emitted its own output.
+ //
+ // Either way, 'Size' will have been set to the amount of data
+ // covered by whatever prologue the target identified. So we advance
+ // our own position to beyond that. Sometimes that will be the entire
+ // 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() << "// Error in decoding " << SymNamesHere[SHI]
<< " : Decoding failed region as bytes.\n";
for (uint64_t I = 0; I < Size; ++I) {
outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true)
<< "\n";
}
}
- } else {
- Size = 0;
+ Start += Size;
+ break;
}
- Start += Size;
-
Index = Start;
if (SectionAddr < StartAddress)
Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);
- // If there is a data/common symbol inside an ELF text section and we are
- // only disassembling text (applicable all architectures), we are in a
- // situation where we must print the data and not disassemble it.
- if (Obj.isELF() && !DisassembleAll && Section.isText()) {
- uint8_t SymTy = Symbols[SI].Type;
- if (SymTy == ELF::STT_OBJECT || SymTy == ELF::STT_COMMON) {
- dumpELFData(SectionAddr, Index, End, Bytes);
- Index = End;
- }
+ if (DisassembleAsData) {
+ dumpELFData(SectionAddr, Index, End, Bytes);
+ Index = End;
+ continue;
}
- bool CheckARMELFData = hasMappingSymbols(Obj) &&
- Symbols[SI].Type != ELF::STT_OBJECT &&
- !DisassembleAll;
bool DumpARMELFData = false;
formatted_raw_ostream FOS(outs());
@@ -1593,7 +1752,7 @@
// 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
// denoted as a word/short etc.
- if (CheckARMELFData) {
+ if (!MappingSymbols.empty()) {
char Kind = getMappingSymbolKind(MappingSymbols, Index);
DumpARMELFData = Kind == 'd';
if (SecondarySTI) {
@@ -1675,7 +1834,7 @@
bool PrintTarget =
MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target);
if (!PrintTarget)
- if (Optional<uint64_t> MaybeTarget =
+ if (std::optional<uint64_t> MaybeTarget =
MIA->evaluateMemoryOperandAddress(
Inst, STI, SectionAddr + Index, Size)) {
Target = *MaybeTarget;
@@ -1729,10 +1888,17 @@
auto It = llvm::partition_point(
*TargetSymbols,
[=](const SymbolInfoTy &O) { return O.Addr <= Target; });
- if (It != TargetSymbols->begin()) {
- TargetSym = &*(It - 1);
- break;
+ while (It != TargetSymbols->begin()) {
+ --It;
+ // Skip mapping symbols to avoid possible ambiguity as they
+ // do not allow uniquely identifying the target address.
+ if (!hasMappingSymbols(Obj) || !isMappingSymbol(*It)) {
+ TargetSym = &*It;
+ break;
+ }
}
+ if (TargetSym)
+ break;
}
// Print the labels corresponding to the target if there's any.
@@ -1824,10 +1990,29 @@
}
static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) {
+ // If information useful for showing the disassembly is missing, try to find a
+ // more complete binary and disassemble that instead.
+ OwningBinary<Binary> FetchedBinary;
+ if (Obj->symbols().empty()) {
+ if (std::optional<OwningBinary<Binary>> FetchedBinaryOpt =
+ fetchBinaryByBuildID(*Obj)) {
+ if (auto *O = dyn_cast<ObjectFile>(FetchedBinaryOpt->getBinary())) {
+ if (!O->symbols().empty() ||
+ (!O->sections().empty() && Obj->sections().empty())) {
+ FetchedBinary = std::move(*FetchedBinaryOpt);
+ Obj = O;
+ }
+ }
+ }
+ }
+
const Target *TheTarget = getTarget(Obj);
// Package up features to be passed to target/subtarget
- SubtargetFeatures Features = Obj->getFeatures();
+ Expected<SubtargetFeatures> FeaturesValue = Obj->getFeatures();
+ if (!FeaturesValue)
+ reportError(FeaturesValue.takeError(), Obj->getFileName());
+ SubtargetFeatures Features = *FeaturesValue;
if (!MAttrs.empty()) {
for (unsigned I = 0; I != MAttrs.size(); ++I)
Features.AddFeature(MAttrs[I]);
@@ -1852,6 +2037,29 @@
if (MCPU.empty())
MCPU = Obj->tryGetCPUName().value_or("").str();
+ if (isArmElf(*Obj)) {
+ // When disassembling big-endian Arm ELF, the instruction endianness is
+ // determined in a complex way. In relocatable objects, AAELF32 mandates
+ // that instruction endianness matches the ELF file endianness; in
+ // executable images, that's true unless the file header has the EF_ARM_BE8
+ // flag, in which case instructions are little-endian regardless of data
+ // endianness.
+ //
+ // We must set the big-endian-instructions SubtargetFeature to make the
+ // disassembler read the instructions the right way round, and also tell
+ // our own prettyprinter to retrieve the encodings the same way to print in
+ // hex.
+ const auto *Elf32BE = dyn_cast<ELF32BEObjectFile>(Obj);
+
+ if (Elf32BE && (Elf32BE->isRelocatableObject() ||
+ !(Elf32BE->getPlatformFlags() & ELF::EF_ARM_BE8))) {
+ Features.AddFeature("+big-endian-instructions");
+ ARMPrettyPrinterInst.setInstructionEndianness(llvm::support::big);
+ } else {
+ ARMPrettyPrinterInst.setInstructionEndianness(llvm::support::little);
+ }
+ }
+
std::unique_ptr<const MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
if (!STI)
@@ -1903,16 +2111,42 @@
IP->setMCInstrAnalysis(MIA.get());
PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
- SourcePrinter SP(Obj, TheTarget->getName());
+
+ const ObjectFile *DbgObj = Obj;
+ if (!FetchedBinary.getBinary() && !Obj->hasDebugInfo()) {
+ if (std::optional<OwningBinary<Binary>> DebugBinaryOpt =
+ fetchBinaryByBuildID(*Obj)) {
+ if (auto *FetchedObj =
+ dyn_cast<const ObjectFile>(DebugBinaryOpt->getBinary())) {
+ if (FetchedObj->hasDebugInfo()) {
+ FetchedBinary = std::move(*DebugBinaryOpt);
+ DbgObj = FetchedObj;
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<object::Binary> DSYMBinary;
+ std::unique_ptr<MemoryBuffer> DSYMBuf;
+ if (!DbgObj->hasDebugInfo()) {
+ if (const MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*Obj)) {
+ DbgObj = objdump::getMachODSymObject(MachOOF, Obj->getFileName(),
+ DSYMBinary, DSYMBuf);
+ if (!DbgObj)
+ return;
+ }
+ }
+
+ SourcePrinter SP(DbgObj, TheTarget->getName());
for (StringRef Opt : DisassemblerOptions)
if (!IP->applyTargetSpecificCLOption(Opt))
reportError(Obj->getFileName(),
"Unrecognized disassembler option: " + Opt);
- disassembleObject(TheTarget, *Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(),
- MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP, SP,
- InlineRelocs);
+ disassembleObject(TheTarget, *Obj, *DbgObj, Ctx, DisAsm.get(),
+ SecondaryDisAsm.get(), MIA.get(), IP.get(), STI.get(),
+ SecondarySTI.get(), PIP, SP, InlineRelocs);
}
void objdump::printRelocations(const ObjectFile *Obj) {
@@ -2026,6 +2260,9 @@
}
void objdump::printSectionHeaders(ObjectFile &Obj) {
+ if (Obj.isELF() && Obj.sections().empty())
+ createFakeELFSections(Obj);
+
size_t NameWidth = getMaxSectionNameWidth(Obj);
size_t AddressWidth = 2 * Obj.getBytesInAddress();
bool HasLMAColumn = shouldDisplayLMA(Obj);
@@ -2038,9 +2275,6 @@
outs() << "Idx " << left_justify("Name", NameWidth) << " Size "
<< left_justify("VMA", AddressWidth) << " Type\n";
- if (Obj.isELF() && Obj.sections().empty())
- createFakeELFSections(Obj);
-
uint64_t Idx;
for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) {
StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName());
@@ -2267,7 +2501,7 @@
StringRef SectionName = unwrapOrError(Section->getName(), FileName);
outs() << SectionName;
if (O.isXCOFF()) {
- Optional<SymbolRef> SymRef =
+ std::optional<SymbolRef> SymRef =
getXCOFFSymbolContainingSymbolRef(cast<XCOFFObjectFile>(O), Symbol);
if (SymRef) {
@@ -2281,8 +2515,8 @@
SymName = demangle(SymName);
if (SymbolDescription)
- SymName = getXCOFFSymbolDescription(
- createSymbolInfo(O, SymRef.value()), SymName);
+ SymName = getXCOFFSymbolDescription(createSymbolInfo(O, *SymRef),
+ SymName);
outs() << ' ' << SymName;
outs() << ") ";
@@ -2373,7 +2607,7 @@
ClangASTSectionName = "clangast";
}
- Optional<object::SectionRef> ClangASTSection;
+ std::optional<object::SectionRef> ClangASTSection;
for (auto Sec : ToolSectionFilter(*Obj)) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Sec.getName())
@@ -2390,7 +2624,7 @@
return;
StringRef ClangASTContents =
- unwrapOrError(ClangASTSection.value().getContents(), Obj->getFileName());
+ unwrapOrError(ClangASTSection->getContents(), Obj->getFileName());
outs().write(ClangASTContents.data(), ClangASTContents.size());
}
@@ -2408,7 +2642,7 @@
return;
}
- Optional<object::SectionRef> FaultMapSection;
+ std::optional<object::SectionRef> FaultMapSection;
for (auto Sec : ToolSectionFilter(*Obj)) {
StringRef Name;
@@ -2705,7 +2939,18 @@
}
}
-static void invalidArgValue(const opt::Arg *A) {
+static object::BuildID parseBuildIDArg(const opt::Arg *A) {
+ StringRef V(A->getValue());
+ std::string Bytes;
+ if (!tryGetFromHex(V, Bytes))
+ reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" +
+ V + "'");
+ ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
+ Bytes.size());
+ return object::BuildID(BuildID.begin(), BuildID.end());
+}
+
+void objdump::invalidArgValue(const opt::Arg *A) {
reportCmdLineError("'" + StringRef(A->getValue()) +
"' is not a valid value for '" + A->getSpelling() + "'");
}
@@ -2757,6 +3002,9 @@
FilterSections.push_back(",__text");
LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X);
+ ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups);
+ DyldInfo = InputArgs.hasArg(OTOOL_dyld_info);
+
InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT);
if (InputFilenames.empty())
reportCmdLineError("no input file");
@@ -2804,10 +3052,11 @@
RawClangAST = InputArgs.hasArg(OBJDUMP_raw_clang_ast);
Relocations = InputArgs.hasArg(OBJDUMP_reloc);
PrintImmHex =
- InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, false);
+ InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, true);
PrivateHeaders = InputArgs.hasArg(OBJDUMP_private_headers);
FilterSections = InputArgs.getAllArgValues(OBJDUMP_section_EQ);
SectionHeaders = InputArgs.hasArg(OBJDUMP_section_headers);
+ ShowAllSymbols = InputArgs.hasArg(OBJDUMP_show_all_symbols);
ShowLMA = InputArgs.hasArg(OBJDUMP_show_lma);
PrintSource = InputArgs.hasArg(OBJDUMP_source);
parseIntArg(InputArgs, OBJDUMP_start_address_EQ, StartAddress);
@@ -2869,6 +3118,17 @@
llvm::cl::ParseCommandLineOptions(2, Argv);
}
+ // Look up any provided build IDs, then append them to the input filenames.
+ for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) {
+ object::BuildID BuildID = parseBuildIDArg(A);
+ std::optional<std::string> Path = BIDFetcher->fetch(BuildID);
+ if (!Path) {
+ reportCmdLineError(A->getSpelling() + ": could not find build ID '" +
+ A->getValue() + "'");
+ }
+ InputFilenames.push_back(std::move(*Path));
+ }
+
// objdump defaults to a.out if no filenames specified.
if (InputFilenames.empty())
InputFilenames.push_back("a.out");
@@ -2936,6 +3196,21 @@
return 0;
}
+ // Initialize debuginfod.
+ const bool ShouldUseDebuginfodByDefault =
+ InputArgs.hasArg(OBJDUMP_build_id) || canUseDebuginfod();
+ std::vector<std::string> DebugFileDirectories =
+ InputArgs.getAllArgValues(OBJDUMP_debug_file_directory);
+ if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod,
+ ShouldUseDebuginfodByDefault)) {
+ HTTPClient::initialize();
+ BIDFetcher =
+ std::make_unique<DebuginfodFetcher>(std::move(DebugFileDirectories));
+ } else {
+ BIDFetcher =
+ std::make_unique<BuildIDFetcher>(std::move(DebugFileDirectories));
+ }
+
if (Is("otool"))
parseOtoolOptions(InputArgs);
else
@@ -2960,11 +3235,12 @@
!DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
!Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
!DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&
- !(MachOOpt && (Bind || DataInCode || DyldInfo || DylibId || DylibsUsed ||
- ExportsTrie || FirstPrivateHeader || FunctionStarts ||
- IndirectSymbols || InfoPlist || LazyBind || LinkOptHints ||
- ObjcMetaData || Rebase || Rpaths || UniversalHeaders ||
- WeakBind || !FilterSections.empty()))) {
+ !(MachOOpt &&
+ (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||
+ DylibsUsed || ExportsTrie || FirstPrivateHeader ||
+ FunctionStartsType != FunctionStartsMode::None || IndirectSymbols ||
+ InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase ||
+ Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) {
T->printHelp(ToolName);
return 2;
}
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 c64c042..efb4451 100644
--- a/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -20,6 +20,10 @@
class StringRef;
class Twine;
+namespace opt {
+class Arg;
+} // namespace opt
+
namespace object {
class RelocationRef;
struct VersionEntry;
@@ -146,6 +150,8 @@
reportError(EO.takeError(), std::forward<Ts>(Args)...);
}
+void invalidArgValue(const opt::Arg *A);
+
std::string getFileNameForError(const object::Archive::Child &C,
unsigned Index);
SymbolInfoTy createSymbolInfo(const object::ObjectFile &Obj,
diff --git a/src/llvm-project/llvm/tools/llvm-opt-fuzzer/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-opt-fuzzer/CMakeLists.txt
index 0ae3d2e..906de66d 100644
--- a/src/llvm-project/llvm/tools/llvm-opt-fuzzer/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-opt-fuzzer/CMakeLists.txt
@@ -21,6 +21,7 @@
ScalarOpts
Support
Target
+ TargetParser
TransformUtils
Vectorize
Passes
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 74b898b..7e8115c 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
@@ -192,14 +192,11 @@
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
- initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
- initializeAggressiveInstCombine(Registry);
- initializeInstrumentation(Registry);
initializeTarget(Registry);
// Parse input options
diff --git a/src/llvm-project/llvm/tools/llvm-opt-report/OptReport.cpp b/src/llvm-project/llvm/tools/llvm-opt-report/OptReport.cpp
index e038863..cc7e60b 100644
--- a/src/llvm-project/llvm/tools/llvm-opt-report/OptReport.cpp
+++ b/src/llvm-project/llvm/tools/llvm-opt-report/OptReport.cpp
@@ -32,6 +32,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <map>
+#include <optional>
#include <set>
using namespace llvm;
@@ -208,7 +209,7 @@
Arg.Val.getAsInteger(10, UnrollCount);
}
- const Optional<remarks::RemarkLocation> &Loc = Remark.Loc;
+ const std::optional<remarks::RemarkLocation> &Loc = Remark.Loc;
if (!Loc)
continue;
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
index a173eb1..4b60420 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -602,7 +602,8 @@
StatCollection TypeStats;
LazyRandomTypeCollection &Types =
opts::dump::DumpTypeStats ? File.types() : File.ids();
- for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+ for (std::optional<TypeIndex> TI = Types.getFirst(); TI;
+ TI = Types.getNext(*TI)) {
CVType Type = Types.getType(*TI);
TypeStats.update(uint32_t(Type.kind()), Type.length());
}
@@ -692,7 +693,7 @@
Kind = kNoneUdtKind;
else if (UDT.Type.isSimple())
Kind = kSimpleUdtKind;
- else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
+ else if (std::optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
Kind = T->kind();
RecordSize = T->length();
} else
@@ -1250,7 +1251,7 @@
if (TI.isSimple()) {
Printer.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Width),
Types.getTypeName(TI));
- } else if (Optional<CVType> Type = Types.tryGetType(TI)) {
+ } else if (std::optional<CVType> Type = Types.tryGetType(TI)) {
if (auto EC = codeview::visitTypeRecord(*Type, TI, V))
Printer.formatLine("An error occurred dumping type record {0}: {1}",
TI, toString(std::move(EC)));
@@ -1517,7 +1518,8 @@
size_t TotalBytes = 0;
size_t RefBytes = 0;
auto &Types = File.types();
- for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+ for (std::optional<TypeIndex> TI = Types.getFirst(); TI;
+ TI = Types.getNext(*TI)) {
CVType Type = File.types().getType(*TI);
TotalBytes += Type.length();
if (RefTracker->isTypeReferenced(*TI)) {
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
index 217d25d..a0c9530 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -13,7 +13,6 @@
#include "StreamUtil.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
index 13a5f6e..3e57e31 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
@@ -124,14 +124,14 @@
return llvm::is_contained(Layout.DirectoryBlocks, pdbBlockIndex());
}
-Optional<uint32_t> ExplainOutputStyle::getPdbBlockStreamIndex() const {
+std::optional<uint32_t> ExplainOutputStyle::getPdbBlockStreamIndex() const {
const auto &Layout = File.pdb().getMsfLayout();
for (const auto &Entry : enumerate(Layout.StreamMap)) {
if (!llvm::is_contained(Entry.value(), pdbBlockIndex()))
continue;
return Entry.index();
}
- return None;
+ return std::nullopt;
}
bool ExplainOutputStyle::explainPdbBlockStatus() {
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
index e3d19f2..499f2a8 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
@@ -43,7 +43,7 @@
bool isPdbFpmBlock() const;
bool isPdbBlockMapBlock() const;
bool isPdbStreamDirectoryBlock() const;
- Optional<uint32_t> getPdbBlockStreamIndex() const;
+ std::optional<uint32_t> getPdbBlockStreamIndex() const;
void explainPdbSuperBlockOffset();
void explainPdbFpmBlockOffset();
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/PdbYaml.h b/src/llvm-project/llvm/tools/llvm-pdbutil/PdbYaml.h
index c335eef..4382e91 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/PdbYaml.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/PdbYaml.h
@@ -11,7 +11,6 @@
#include "OutputStyle.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
@@ -24,6 +23,7 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/YAMLTraits.h"
+#include <optional>
#include <vector>
namespace llvm {
@@ -67,7 +67,7 @@
StringRef Mod;
std::vector<StringRef> SourceFiles;
std::vector<CodeViewYAML::YAMLDebugSubsection> Subsections;
- Optional<PdbModiStream> Modi;
+ std::optional<PdbModiStream> Modi;
};
struct PdbDbiStream {
@@ -94,16 +94,16 @@
struct PdbObject {
explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {}
- Optional<MSFHeaders> Headers;
- Optional<std::vector<uint32_t>> StreamSizes;
- Optional<std::vector<StreamBlockList>> StreamMap;
- Optional<PdbInfoStream> PdbStream;
- Optional<PdbDbiStream> DbiStream;
- Optional<PdbTpiStream> TpiStream;
- Optional<PdbTpiStream> IpiStream;
- Optional<PdbPublicsStream> PublicsStream;
+ std::optional<MSFHeaders> Headers;
+ std::optional<std::vector<uint32_t>> StreamSizes;
+ std::optional<std::vector<StreamBlockList>> StreamMap;
+ std::optional<PdbInfoStream> PdbStream;
+ std::optional<PdbDbiStream> DbiStream;
+ std::optional<PdbTpiStream> TpiStream;
+ std::optional<PdbTpiStream> IpiStream;
+ std::optional<PdbPublicsStream> PublicsStream;
- Optional<std::vector<StringRef>> StringTable;
+ std::optional<std::vector<StringRef>> StringTable;
BumpPtrAllocator &Allocator;
};
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
index 2285ed1..06792f9 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
@@ -66,7 +66,7 @@
if (BaseCount > 0) {
Printer.Indent();
char NextSeparator = ':';
- for (auto BC : Layout.bases()) {
+ for (auto *BC : Layout.bases()) {
const auto &Base = BC->getBase();
if (Base.isIndirectVirtualBaseClass())
continue;
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
index 1ade7f3..c420283 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
@@ -36,16 +36,16 @@
if (RecursionLevel == 1 &&
opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
- for (auto &Other : Layout.other_items())
+ for (const auto &Other : Layout.other_items())
Other->dump(*this);
- for (auto &Func : Layout.funcs())
+ for (const auto &Func : Layout.funcs())
Func->dump(*this);
}
const BitVector &UseMap = Layout.usedBytes();
int NextPaddingByte = UseMap.find_first_unset();
- for (auto &Item : Layout.layout_items()) {
+ for (const auto &Item : Layout.layout_items()) {
// Calculate the absolute offset of the first byte of the next field.
uint32_t RelativeOffset = Item->getOffsetInParent();
CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.h b/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.h
index f810f7d..9d6030c 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/StreamUtil.h
@@ -9,11 +9,11 @@
#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <string>
+#include <optional>
namespace llvm {
namespace pdb {
@@ -52,7 +52,7 @@
StreamPurpose Purpose;
uint32_t StreamIndex;
std::string Name;
- Optional<uint32_t> ModuleIndex;
+ std::optional<uint32_t> ModuleIndex;
};
void discoverStreamPurposes(PDBFile &File,
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp b/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
index d813bc2..5ae720a 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
@@ -24,7 +24,8 @@
// just iterate up front to find out.
static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) {
uint32_t NumTypes = 0;
- for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI))
+ for (std::optional<TypeIndex> TI = Types.getFirst(); TI;
+ TI = Types.getNext(*TI))
++NumTypes;
return NumTypes;
}
@@ -129,9 +130,9 @@
TiRefKind RefKind;
TypeIndex RefTI;
std::tie(RefKind, RefTI) = RefWorklist.pop_back_val();
- Optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)
- ? Ids->tryGetType(RefTI)
- : Types.tryGetType(RefTI);
+ std::optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)
+ ? Ids->tryGetType(RefTI)
+ : Types.tryGetType(RefTI);
if (!Rec)
continue; // FIXME: Report a reference to a non-existant type.
diff --git a/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h b/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h
index c586f65..8262129 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h
@@ -10,7 +10,6 @@
#define LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
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 3859558..61cad15 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -377,8 +377,8 @@
cl::OptionCategory Types("Type Options");
cl::OptionCategory ModuleCategory("Module Options");
-llvm::Optional<NumberRange> DumpBlockRange;
-llvm::Optional<NumberRange> DumpByteRange;
+std::optional<NumberRange> DumpBlockRange;
+std::optional<NumberRange> DumpByteRange;
cl::opt<std::string> DumpBlockRangeOpt(
"block-range", cl::value_desc("start[-end]"),
@@ -865,7 +865,7 @@
AppendingTypeTableBuilder TS(Allocator);
for (const auto &R : Tpi.Records) {
CVType Type = R.toCodeViewRecord(TS);
- TpiBuilder.addTypeRecord(Type.RecordData, None);
+ TpiBuilder.addTypeRecord(Type.RecordData, std::nullopt);
}
const auto &Ipi = YamlObj.IpiStream.value_or(DefaultIpiStream);
@@ -873,7 +873,7 @@
IpiBuilder.setVersionHeader(Ipi.Version);
for (const auto &R : Ipi.Records) {
CVType Type = R.toCodeViewRecord(TS);
- IpiBuilder.addTypeRecord(Type.RecordData, None);
+ IpiBuilder.addTypeRecord(Type.RecordData, std::nullopt);
}
Builder.getStringTableBuilder().setStrings(*Strings.strings());
@@ -1353,10 +1353,10 @@
auto &DestTpi = Builder.getTpiBuilder();
auto &DestIpi = Builder.getIpiBuilder();
MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, const CVType &Type) {
- DestTpi.addTypeRecord(Type.RecordData, None);
+ DestTpi.addTypeRecord(Type.RecordData, std::nullopt);
});
MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, const CVType &Type) {
- DestIpi.addTypeRecord(Type.RecordData, None);
+ DestIpi.addTypeRecord(Type.RecordData, std::nullopt);
});
Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140);
@@ -1422,7 +1422,7 @@
}
static bool parseRange(StringRef Str,
- Optional<opts::bytes::NumberRange> &Parsed) {
+ std::optional<opts::bytes::NumberRange> &Parsed) {
if (Str.empty())
return true;
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 455fe5f..8766d70 100644
--- a/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/src/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -10,7 +10,6 @@
#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
#include "llvm/Support/CommandLine.h"
@@ -111,11 +110,11 @@
namespace bytes {
struct NumberRange {
uint64_t Min;
- llvm::Optional<uint64_t> Max;
+ std::optional<uint64_t> Max;
};
-extern llvm::Optional<NumberRange> DumpBlockRange;
-extern llvm::Optional<NumberRange> DumpByteRange;
+extern std::optional<NumberRange> DumpBlockRange;
+extern std::optional<NumberRange> DumpByteRange;
extern llvm::cl::list<std::string> DumpStreamData;
extern llvm::cl::opt<bool> NameMap;
extern llvm::cl::opt<bool> Fpm;
diff --git a/src/llvm-project/llvm/tools/llvm-profdata/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-profdata/CMakeLists.txt
index 3545bde..0cf36d1 100644
--- a/src/llvm-project/llvm/tools/llvm-profdata/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-profdata/CMakeLists.txt
@@ -11,4 +11,5 @@
DEPENDS
intrinsics_gen
+ GENERATE_DRIVER
)
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 3af8f80..c8e5e6d 100644
--- a/src/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -13,7 +13,6 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/Binary.h"
#include "llvm/ProfileData/InstrProfCorrelator.h"
@@ -31,6 +30,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MD5.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ThreadPool.h"
@@ -38,10 +38,16 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <cmath>
+#include <optional>
#include <queue>
using namespace llvm;
+// We use this string to indicate that there are
+// multiple static functions map to the same name.
+const std::string DuplicateNameStr = "----";
+
enum ProfileFormat {
PF_None = 0,
PF_Text,
@@ -51,6 +57,8 @@
PF_Binary
};
+enum class ShowFormat { Text, Json, Yaml };
+
static void warn(Twine Message, std::string Whence = "",
std::string Hint = "") {
WithColor::warning();
@@ -329,9 +337,16 @@
FuncName, firstTime);
});
}
- if (Reader->hasError())
+
+ if (Reader->hasError()) {
if (Error E = Reader->getError())
WC->Errors.emplace_back(std::move(E), Filename);
+ }
+
+ std::vector<llvm::object::BuildID> BinaryIds;
+ if (Error E = Reader->readBinaryIds(BinaryIds))
+ WC->Errors.emplace_back(std::move(E), Filename);
+ WC->Writer.addBinaryIds(BinaryIds);
}
/// Merge the \p Src writer context into \p Dst.
@@ -340,6 +355,9 @@
Dst->Errors.push_back(std::move(ErrorPair));
Src->Errors.clear();
+ if (Error E = Dst->Writer.mergeProfileKind(Src->Writer.getProfileKind()))
+ exitWithError(std::move(E));
+
Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer), [&](Error E) {
instrprof_error IPE = InstrProfError::take(std::move(E));
std::unique_lock<std::mutex> ErrGuard{Dst->ErrLock};
@@ -397,9 +415,6 @@
if (NumThreads == 0)
NumThreads = std::min(hardware_concurrency().compute_thread_count(),
unsigned((Inputs.size() + 1) / 2));
- // FIXME: There's a bug here, where setting NumThreads = Inputs.size() fails
- // the merge_empty_profile.test because the InstrProfWriter.ProfileKind isn't
- // merged, thus the emitted file ends up with a PF_Unknown kind.
// Initialize the writer contexts.
SmallVector<std::unique_ptr<WriterContext>, 4> Contexts;
@@ -461,6 +476,7 @@
/// The profile entry for a function in instrumentation profile.
struct InstrProfileEntry {
uint64_t MaxCount = 0;
+ uint64_t NumEdgeCounters = 0;
float ZeroCounterRatio = 0.0;
InstrProfRecord *ProfRecord;
InstrProfileEntry(InstrProfRecord *Record);
@@ -476,33 +492,49 @@
ZeroCntNum += !Record->Counts[I];
}
ZeroCounterRatio = (float)ZeroCntNum / CntNum;
+ NumEdgeCounters = CntNum;
}
-/// Either set all the counters in the instr profile entry \p IFE to -1
-/// in order to drop the profile or scale up the counters in \p IFP to
-/// be above hot threshold. We use the ratio of zero counters in the
-/// profile of a function to decide the profile is helpful or harmful
-/// for performance, and to choose whether to scale up or drop it.
-static void updateInstrProfileEntry(InstrProfileEntry &IFE,
+/// Either set all the counters in the instr profile entry \p IFE to
+/// -1 / -2 /in order to drop the profile or scale up the
+/// counters in \p IFP to be above hot / cold threshold. We use
+/// the ratio of zero counters in the profile of a function to
+/// decide the profile is helpful or harmful for performance,
+/// and to choose whether to scale up or drop it.
+static void updateInstrProfileEntry(InstrProfileEntry &IFE, bool SetToHot,
uint64_t HotInstrThreshold,
+ uint64_t ColdInstrThreshold,
float ZeroCounterThreshold) {
InstrProfRecord *ProfRecord = IFE.ProfRecord;
if (!IFE.MaxCount || IFE.ZeroCounterRatio > ZeroCounterThreshold) {
// If all or most of the counters of the function are zero, the
- // profile is unaccountable and shuld be dropped. Reset all the
- // counters to be -1 and PGO profile-use will drop the profile.
+ // profile is unaccountable and should be dropped. Reset all the
+ // counters to be -1 / -2 and PGO profile-use will drop the profile.
// All counters being -1 also implies that the function is hot so
// PGO profile-use will also set the entry count metadata to be
// above hot threshold.
- for (size_t I = 0; I < ProfRecord->Counts.size(); ++I)
- ProfRecord->Counts[I] = -1;
+ // All counters being -2 implies that the function is warm so
+ // PGO profile-use will also set the entry count metadata to be
+ // above cold threshold.
+ auto Kind =
+ (SetToHot ? InstrProfRecord::PseudoHot : InstrProfRecord::PseudoWarm);
+ ProfRecord->setPseudoCount(Kind);
return;
}
- // Scale up the MaxCount to be multiple times above hot threshold.
+ // Scale up the MaxCount to be multiple times above hot / cold threshold.
const unsigned MultiplyFactor = 3;
- uint64_t Numerator = HotInstrThreshold * MultiplyFactor;
+ uint64_t Threshold = (SetToHot ? HotInstrThreshold : ColdInstrThreshold);
+ uint64_t Numerator = Threshold * MultiplyFactor;
+
+ // Make sure Threshold for warm counters is below the HotInstrThreshold.
+ if (!SetToHot && Threshold >= HotInstrThreshold) {
+ Threshold = (HotInstrThreshold + ColdInstrThreshold) / 2;
+ }
+
uint64_t Denominator = IFE.MaxCount;
+ if (Numerator <= Denominator)
+ return;
ProfRecord->scale(Numerator, Denominator, [&](instrprof_error E) {
warn(toString(make_error<InstrProfError>(E)));
});
@@ -539,7 +571,167 @@
unsigned InstrProfColdThreshold) {
// Function to its entry in instr profile.
StringMap<InstrProfileEntry> InstrProfileMap;
+ StringMap<StringRef> StaticFuncMap;
InstrProfSummaryBuilder IPBuilder(ProfileSummaryBuilder::DefaultCutoffs);
+
+ auto checkSampleProfileHasFUnique = [&Reader]() {
+ for (const auto &PD : Reader->getProfiles()) {
+ auto &FContext = PD.first;
+ if (FContext.toString().find(FunctionSamples::UniqSuffix) !=
+ std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ bool SampleProfileHasFUnique = checkSampleProfileHasFUnique();
+
+ auto buildStaticFuncMap = [&StaticFuncMap,
+ SampleProfileHasFUnique](const StringRef Name) {
+ std::string Prefixes[] = {".cpp:", "cc:", ".c:", ".hpp:", ".h:"};
+ size_t PrefixPos = StringRef::npos;
+ for (auto &Prefix : Prefixes) {
+ PrefixPos = Name.find_insensitive(Prefix);
+ if (PrefixPos == StringRef::npos)
+ continue;
+ PrefixPos += Prefix.size();
+ break;
+ }
+
+ if (PrefixPos == StringRef::npos) {
+ return;
+ }
+
+ StringRef NewName = Name.drop_front(PrefixPos);
+ StringRef FName = Name.substr(0, PrefixPos - 1);
+ if (NewName.size() == 0) {
+ return;
+ }
+
+ // This name should have a static linkage.
+ size_t PostfixPos = NewName.find(FunctionSamples::UniqSuffix);
+ bool ProfileHasFUnique = (PostfixPos != StringRef::npos);
+
+ // If sample profile and instrumented profile do not agree on symbol
+ // uniqification.
+ if (SampleProfileHasFUnique != ProfileHasFUnique) {
+ // If instrumented profile uses -funique-internal-linakge-symbols,
+ // we need to trim the name.
+ if (ProfileHasFUnique) {
+ NewName = NewName.substr(0, PostfixPos);
+ } else {
+ // If sample profile uses -funique-internal-linakge-symbols,
+ // we build the map.
+ std::string NStr =
+ NewName.str() + getUniqueInternalLinkagePostfix(FName);
+ NewName = StringRef(NStr);
+ StaticFuncMap[NewName] = Name;
+ return;
+ }
+ }
+
+ if (StaticFuncMap.find(NewName) == StaticFuncMap.end()) {
+ StaticFuncMap[NewName] = Name;
+ } else {
+ StaticFuncMap[NewName] = DuplicateNameStr;
+ }
+ };
+
+ // We need to flatten the SampleFDO profile as the InstrFDO
+ // profile does not have inlined callsite profiles.
+ // One caveat is the pre-inlined function -- their samples
+ // should be collapsed into the caller function.
+ // Here we do a DFS traversal to get the flatten profile
+ // info: the sum of entrycount and the max of maxcount.
+ // Here is the algorithm:
+ // recursive (FS, root_name) {
+ // name = FS->getName();
+ // get samples for FS;
+ // if (InstrProf.find(name) {
+ // root_name = name;
+ // } else {
+ // if (name is in static_func map) {
+ // root_name = static_name;
+ // }
+ // }
+ // update the Map entry for root_name;
+ // for (subfs: FS) {
+ // recursive(subfs, root_name);
+ // }
+ // }
+ //
+ // Here is an example.
+ //
+ // SampleProfile:
+ // foo:12345:1000
+ // 1: 1000
+ // 2.1: 1000
+ // 15: 5000
+ // 4: bar:1000
+ // 1: 1000
+ // 2: goo:3000
+ // 1: 3000
+ // 8: bar:40000
+ // 1: 10000
+ // 2: goo:30000
+ // 1: 30000
+ //
+ // InstrProfile has two entries:
+ // foo
+ // bar.cc:bar
+ //
+ // After BuildMaxSampleMap, we should have the following in FlattenSampleMap:
+ // {"foo", {1000, 5000}}
+ // {"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
+ // 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
+ // entry in InstrProfile.
+ DenseMap<StringRef, 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();
+ const StringRef *NewRootName = &RootName;
+ uint64_t EntrySample = FS.getHeadSamplesEstimate();
+ uint64_t MaxBodySample = FS.getMaxCountInside(/* SkipCallSite*/ true);
+
+ auto It = InstrProfileMap.find(Name);
+ if (It != InstrProfileMap.end()) {
+ NewRootName = &Name;
+ } else {
+ auto NewName = StaticFuncMap.find(Name);
+ if (NewName != StaticFuncMap.end()) {
+ It = InstrProfileMap.find(NewName->second.str());
+ if (NewName->second != DuplicateNameStr) {
+ NewRootName = &NewName->second;
+ }
+ } else {
+ // Here the EntrySample is of an inlined function, so we should not
+ // update the EntrySample in the map.
+ EntrySample = 0;
+ }
+ }
+ EntrySample += FlattenSampleMap[*NewRootName].first;
+ MaxBodySample =
+ std::max(FlattenSampleMap[*NewRootName].second, MaxBodySample);
+ FlattenSampleMap[*NewRootName] =
+ std::make_pair(EntrySample, MaxBodySample);
+
+ for (const auto &C : FS.getCallsiteSamples())
+ for (const auto &F : C.second)
+ BuildImpl(F.second, *NewRootName, BuildImpl);
+ };
+ BuildMaxSampleMapImpl(FS, RootName, BuildMaxSampleMapImpl);
+ };
+
for (auto &PD : WC->Writer.getProfileData()) {
// Populate IPBuilder.
for (const auto &PDV : PD.getValue()) {
@@ -553,13 +745,25 @@
// Initialize InstrProfileMap.
InstrProfRecord *R = &PD.getValue().begin()->second;
- InstrProfileMap[PD.getKey()] = InstrProfileEntry(R);
+ StringRef FullName = PD.getKey();
+ InstrProfileMap[FullName] = InstrProfileEntry(R);
+ buildStaticFuncMap(FullName);
+ }
+
+ for (auto &PD : Reader->getProfiles()) {
+ sampleprof::FunctionSamples &FS = PD.second;
+ BuildMaxSampleMap(FS, FS.getName());
}
ProfileSummary InstrPS = *IPBuilder.getSummary();
ProfileSummary SamplePS = Reader->getSummary();
// Compute cold thresholds for instr profile and sample profile.
+ uint64_t HotSampleThreshold =
+ ProfileSummaryBuilder::getEntryForPercentile(
+ SamplePS.getDetailedSummary(),
+ ProfileSummaryBuilder::DefaultCutoffs[HotPercentileIdx])
+ .MinCount;
uint64_t ColdSampleThreshold =
ProfileSummaryBuilder::getEntryForPercentile(
SamplePS.getDetailedSummary(),
@@ -580,17 +784,30 @@
// Find hot/warm functions in sample profile which is cold in instr profile
// and adjust the profiles of those functions in the instr profile.
- for (const auto &PD : Reader->getProfiles()) {
- auto &FContext = PD.first;
- const sampleprof::FunctionSamples &FS = PD.second;
- auto It = InstrProfileMap.find(FContext.toString());
- if (FS.getHeadSamples() > ColdSampleThreshold &&
- It != InstrProfileMap.end() &&
- It->second.MaxCount <= ColdInstrThreshold &&
- FS.getBodySamples().size() >= SupplMinSizeThreshold) {
- updateInstrProfileEntry(It->second, HotInstrThreshold,
- ZeroCounterThreshold);
+ for (const auto &E : FlattenSampleMap) {
+ uint64_t SampleMaxCount = std::max(E.second.first, E.second.second);
+ if (SampleMaxCount < ColdSampleThreshold)
+ continue;
+ const StringRef &Name = E.first;
+ auto It = InstrProfileMap.find(Name);
+ if (It == InstrProfileMap.end()) {
+ auto NewName = StaticFuncMap.find(Name);
+ if (NewName != StaticFuncMap.end()) {
+ It = InstrProfileMap.find(NewName->second.str());
+ if (NewName->second == DuplicateNameStr) {
+ WithColor::warning()
+ << "Static function " << Name
+ << " has multiple promoted names, cannot adjust profile.\n";
+ }
+ }
}
+ if (It == InstrProfileMap.end() ||
+ It->second.MaxCount > ColdInstrThreshold ||
+ It->second.NumEdgeCounters < SupplMinSizeThreshold)
+ continue;
+ bool SetToHot = SampleMaxCount >= HotSampleThreshold;
+ updateInstrProfileEntry(It->second, SetToHot, HotInstrThreshold,
+ ColdInstrThreshold, ZeroCounterThreshold);
}
}
@@ -748,14 +965,15 @@
StringRef ProfileSymbolListFile, bool CompressAllSections,
bool UseMD5, bool GenPartialProfile, bool GenCSNestedProfile,
bool SampleMergeColdContext, bool SampleTrimColdContext,
- bool SampleColdContextFrameDepth, FailureMode FailMode) {
+ bool SampleColdContextFrameDepth, FailureMode FailMode,
+ bool DropProfileSymbolList) {
using namespace sampleprof;
SampleProfileMap ProfileMap;
SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;
LLVMContext Context;
sampleprof::ProfileSymbolList WriterList;
- Optional<bool> ProfileIsProbeBased;
- Optional<bool> ProfileIsCS;
+ std::optional<bool> ProfileIsProbeBased;
+ std::optional<bool> ProfileIsCS;
for (const auto &Input : Inputs) {
auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context,
FSDiscriminatorPassOption);
@@ -801,10 +1019,12 @@
}
}
- std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList =
- Reader->getProfileSymbolList();
- if (ReaderList)
- WriterList.merge(*ReaderList);
+ if (!DropProfileSymbolList) {
+ std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList =
+ Reader->getProfileSymbolList();
+ if (ReaderList)
+ WriterList.merge(*ReaderList);
+ }
}
if (ProfileIsCS && (SampleMergeColdContext || SampleTrimColdContext)) {
@@ -1016,6 +1236,10 @@
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)"));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
@@ -1060,11 +1284,11 @@
OutputFilename, OutputFormat, OutputSparse, NumThreads,
FailureMode, ProfiledBinary);
else
- mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename,
- OutputFormat, ProfileSymbolListFile, CompressAllSections,
- UseMD5, GenPartialProfile, GenCSNestedProfile,
- SampleMergeColdContext, SampleTrimColdContext,
- SampleColdContextFrameDepth, FailureMode);
+ mergeSampleProfile(
+ WeightedInputs, Remapper.get(), OutputFilename, OutputFormat,
+ ProfileSymbolListFile, CompressAllSections, UseMD5, GenPartialProfile,
+ GenCSNestedProfile, SampleMergeColdContext, SampleTrimColdContext,
+ SampleColdContextFrameDepth, FailureMode, DropProfileSymbolList);
return 0;
}
@@ -2142,7 +2366,12 @@
uint64_t ValueCutoff, bool OnlyListBelow,
const std::string &ShowFunction, bool TextFormat,
bool ShowBinaryIds, bool ShowCovered,
+ bool ShowProfileVersion, ShowFormat SFormat,
raw_fd_ostream &OS) {
+ if (SFormat == ShowFormat::Json)
+ exitWithError("JSON output is not supported for instr profiles");
+ if (SFormat == ShowFormat::Yaml)
+ exitWithError("YAML output is not supported for instr profiles");
auto ReaderOrErr = InstrProfReader::create(Filename);
std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
if (ShowDetailedSummary && Cutoffs.empty()) {
@@ -2207,9 +2436,27 @@
uint64_t FuncMax = 0;
uint64_t FuncSum = 0;
+
+ auto PseudoKind = Func.getCountPseudoKind();
+ if (PseudoKind != InstrProfRecord::NotPseudo) {
+ if (Show) {
+ if (!ShownFunctions)
+ OS << "Counters:\n";
+ ++ShownFunctions;
+ OS << " " << Func.Name << ":\n"
+ << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
+ << " Counters: " << Func.Counts.size();
+ if (PseudoKind == InstrProfRecord::PseudoHot)
+ OS << " <PseudoHot>\n";
+ else if (PseudoKind == InstrProfRecord::PseudoWarm)
+ OS << " <PseudoWarm>\n";
+ else
+ llvm_unreachable("Unknown PseudoKind");
+ }
+ continue;
+ }
+
for (size_t I = 0, E = Func.Counts.size(); I < E; ++I) {
- if (Func.Counts[I] == (uint64_t)-1)
- continue;
FuncMax = std::max(FuncMax, Func.Counts[I]);
FuncSum += Func.Counts[I];
}
@@ -2334,6 +2581,8 @@
if (Error E = Reader->printBinaryIds(OS))
exitWithError(std::move(E), Filename);
+ if (ShowProfileVersion)
+ OS << "Profile version: " << Reader->getVersion() << "\n";
return 0;
}
@@ -2488,7 +2737,9 @@
const std::string &ShowFunction,
bool ShowProfileSymbolList,
bool ShowSectionInfoOnly, bool ShowHotFuncList,
- raw_fd_ostream &OS) {
+ ShowFormat SFormat, raw_fd_ostream &OS) {
+ if (SFormat == ShowFormat::Yaml)
+ exitWithError("YAML output is not supported for sample profiles");
using namespace sampleprof;
LLVMContext Context;
auto ReaderOrErr =
@@ -2505,11 +2756,20 @@
if (std::error_code EC = Reader->read())
exitWithErrorCode(EC, Filename);
- if (ShowAllFunctions || ShowFunction.empty())
- Reader->dump(OS);
- else
+ if (ShowAllFunctions || ShowFunction.empty()) {
+ if (SFormat == ShowFormat::Json)
+ Reader->dumpJson(OS);
+ else
+ Reader->dump(OS);
+ } else {
+ if (SFormat == ShowFormat::Json)
+ exitWithError(
+ "the JSON format is supported only when all functions are to "
+ "be printed");
+
// TODO: parse context string to support filtering by contexts.
Reader->dumpFunctionProfile(StringRef(ShowFunction), OS);
+ }
if (ShowProfileSymbolList) {
std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList =
@@ -2531,7 +2791,9 @@
static int showMemProfProfile(const std::string &Filename,
const std::string &ProfiledBinary,
- raw_fd_ostream &OS) {
+ ShowFormat SFormat, raw_fd_ostream &OS) {
+ if (SFormat == ShowFormat::Json)
+ exitWithError("JSON output is not supported for MemProf");
auto ReaderOr = llvm::memprof::RawMemProfReader::create(
Filename, ProfiledBinary, /*KeepNames=*/true);
if (Error E = ReaderOr.takeError())
@@ -2550,10 +2812,18 @@
static int showDebugInfoCorrelation(const std::string &Filename,
bool ShowDetailedSummary,
bool ShowProfileSymbolList,
- raw_fd_ostream &OS) {
+ 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))
exitWithError(std::move(Err), Filename);
+ if (SFormat == ShowFormat::Yaml) {
+ if (auto Err = Correlator->dumpYaml(OS))
+ exitWithError(std::move(Err), Filename);
+ return 0;
+ }
+
if (auto Err = Correlator->correlateProfileData())
exitWithError(std::move(Err), Filename);
@@ -2579,9 +2849,20 @@
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"));
@@ -2646,7 +2927,8 @@
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())
@@ -2659,6 +2941,8 @@
<< ": Input file name cannot be the same as the output file name!\n";
return 1;
}
+ if (JsonFormat)
+ SFormat = ShowFormat::Json;
std::error_code EC;
raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
@@ -2670,23 +2954,25 @@
if (!DebugInfoFilename.empty())
return showDebugInfoCorrelation(DebugInfoFilename, ShowDetailedSummary,
- ShowProfileSymbolList, OS);
+ ShowProfileSymbolList, SFormat, OS);
if (ProfileKind == instr)
return showInstrProfile(
Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets,
ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs,
ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction,
- TextFormat, ShowBinaryIds, ShowCovered, OS);
+ TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion, SFormat,
+ OS);
if (ProfileKind == sample)
return showSampleProfile(Filename, ShowCounts, TopNFunctions,
ShowAllFunctions, ShowDetailedSummary,
ShowFunction, ShowProfileSymbolList,
- ShowSectionInfoOnly, ShowHotFuncList, OS);
- return showMemProfProfile(Filename, ProfiledBinary, OS);
+ ShowSectionInfoOnly, ShowHotFuncList, SFormat, OS);
+ return showMemProfProfile(Filename, ProfiledBinary, SFormat, OS);
}
-int main(int argc, const char *argv[]) {
+int llvm_profdata_main(int argc, char **argvNonConst) {
+ const char **argv = const_cast<const char **>(argvNonConst);
InitLLVM X(argc, argv);
StringRef ProgName(sys::path::filename(argv[0]));
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-profgen/CMakeLists.txt
index b3e05a9..354c63f 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-profgen/CMakeLists.txt
@@ -12,6 +12,7 @@
ProfileData
Support
Symbolize
+ TargetParser
)
add_llvm_tool(llvm-profgen
@@ -20,4 +21,5 @@
CSPreInliner.cpp
ProfiledBinary.cpp
ProfileGenerator.cpp
+ MissingFrameInferrer.cpp
)
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp b/src/llvm-project/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp
new file mode 100644
index 0000000..4127fdc
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp
@@ -0,0 +1,318 @@
+//===-- MissingFrameInferrer.cpp - Missing frame inferrer --------- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "MissingFrameInferrer.h"
+#include "PerfReader.h"
+#include "ProfiledBinary.h"
+#include "llvm/ADT/SCCIterator.h"
+#include "llvm/ADT/Statistic.h"
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <queue>
+#include <sys/types.h>
+
+#define DEBUG_TYPE "missing-frame-inferrer"
+
+using namespace llvm;
+using namespace sampleprof;
+
+STATISTIC(TailCallUniReachable,
+ "Number of frame pairs reachable via a unique tail call path");
+STATISTIC(TailCallMultiReachable,
+ "Number of frame pairs reachable via a multiple tail call paths");
+STATISTIC(TailCallUnreachable,
+ "Number of frame pairs unreachable via any tail call path");
+STATISTIC(TailCallFuncSingleTailCalls,
+ "Number of functions with single tail call site");
+STATISTIC(TailCallFuncMultipleTailCalls,
+ "Number of functions with multiple tail call sites");
+STATISTIC(TailCallMaxTailCallPath, "Length of the longest tail call path");
+
+static cl::opt<uint32_t>
+ MaximumSearchDepth("max-search-depth", cl::init(UINT32_MAX - 1),
+ cl::desc("The maximum levels the DFS-based missing "
+ "frame search should go with"));
+
+void MissingFrameInferrer::initialize(
+ const ContextSampleCounterMap *SampleCounters) {
+ // Refine call edges based on LBR samples.
+ if (SampleCounters) {
+ std::unordered_map<uint64_t, std::unordered_set<uint64_t>> SampledCalls;
+ std::unordered_map<uint64_t, std::unordered_set<uint64_t>> SampledTailCalls;
+
+ // Populate SampledCalls based on static call sites. Similarly to
+ // SampledTailCalls.
+ for (const auto &CI : *SampleCounters) {
+ for (auto Item : CI.second.BranchCounter) {
+ auto From = Item.first.first;
+ auto To = Item.first.second;
+ if (CallEdges.count(From)) {
+ assert(CallEdges[From].size() == 1 &&
+ "A callsite should only appear once with either a known or a "
+ "zero (unknown) target value at this point");
+ SampledCalls[From].insert(To);
+ }
+ if (TailCallEdges.count(From)) {
+ assert(TailCallEdges[From].size() == 1 &&
+ "A callsite should only appear once with either a known or a "
+ "zero (unknown) target value at this point");
+ FuncRange *FromFRange = Binary->findFuncRange(From);
+ FuncRange *ToFRange = Binary->findFuncRange(To);
+ if (FromFRange != ToFRange)
+ SampledTailCalls[From].insert(To);
+ }
+ }
+ }
+
+ // Replace static edges with dynamic edges.
+ CallEdges = SampledCalls;
+ TailCallEdges = SampledTailCalls;
+ }
+
+ // Populate function-based edges. This is to speed up address to function
+ // translation.
+ for (auto Call : CallEdges)
+ for (auto Target : Call.second)
+ if (FuncRange *ToFRange = Binary->findFuncRange(Target))
+ CallEdgesF[Call.first].insert(ToFRange->Func);
+
+ for (auto Call : TailCallEdges) {
+ for (auto Target : Call.second) {
+ if (FuncRange *ToFRange = Binary->findFuncRange(Target)) {
+ TailCallEdgesF[Call.first].insert(ToFRange->Func);
+ TailCallTargetFuncs.insert(ToFRange->Func);
+ }
+ }
+ if (FuncRange *FromFRange = Binary->findFuncRange(Call.first))
+ FuncToTailCallMap[FromFRange->Func].push_back(Call.first);
+ }
+
+#if LLVM_ENABLE_STATS
+ for (auto F : FuncToTailCallMap) {
+ assert(F.second.size() > 0 && "");
+ if (F.second.size() > 1)
+ TailCallFuncMultipleTailCalls++;
+ else
+ TailCallFuncSingleTailCalls++;
+ }
+#endif
+
+#ifndef NDEBUG
+ auto PrintCallTargets =
+ [&](const std::unordered_map<uint64_t, std::unordered_set<uint64_t>>
+ &CallTargets,
+ bool IsTailCall) {
+ for (const auto &Targets : CallTargets) {
+ for (const auto &Target : Targets.second) {
+ dbgs() << (IsTailCall ? "TailCall" : "Call");
+ dbgs() << " From " << format("%8" PRIx64, Targets.first) << " to "
+ << format("%8" PRIx64, Target) << "\n";
+ }
+ }
+ };
+
+ LLVM_DEBUG(dbgs() << "============================\n ";
+ dbgs() << "Call targets:\n";
+ PrintCallTargets(CallEdges, false);
+ dbgs() << "\nTail call targets:\n";
+ PrintCallTargets(CallEdges, true);
+ dbgs() << "============================\n";);
+#endif
+}
+
+uint64_t MissingFrameInferrer::computeUniqueTailCallPath(
+ BinaryFunction *From, BinaryFunction *To, SmallVectorImpl<uint64_t> &Path) {
+ // Search for a unique path comprised of only tail call edges for a given
+ // source and target frame address on the a tail call graph that consists of
+ // only tail call edges. Note that only a unique path counts. Multiple paths
+ // are treated unreachable.
+ if (From == To)
+ return 1;
+
+ // Ignore cyclic paths. Since we are doing a recursive DFS walk, if the source
+ // frame being visited is already in the stack, it means we are seeing a
+ // cycle. This is done before querying the cached result because the cached
+ // result may be computed based on the same path. Consider the following case:
+ // A -> B, B -> A, A -> D
+ // When computing unique reachablity from A to D, the cached result for (B,D)
+ // should not be counted since the unique path B->A->D is basically the same
+ // path as A->D. Counting that with invalidate the uniqueness from A to D.
+ if (Visiting.contains(From))
+ return 0;
+
+ // If already computed, return the cached result.
+ auto I = UniquePaths.find({From, To});
+ if (I != UniquePaths.end()) {
+ Path.append(I->second.begin(), I->second.end());
+ return 1;
+ }
+
+ auto J = NonUniquePaths.find({From, To});
+ if (J != NonUniquePaths.end()) {
+ return J->second;
+ }
+
+ uint64_t Pos = Path.size();
+
+ // DFS walk each outgoing tail call edges.
+ // Bail out if we are already at the the maximum searching depth.
+ if (CurSearchingDepth == MaximumSearchDepth)
+ return 0;
+
+
+ if (!FuncToTailCallMap.count(From))
+ return 0;
+
+ CurSearchingDepth++;
+ Visiting.insert(From);
+ uint64_t NumPaths = 0;
+ for (auto TailCall : FuncToTailCallMap[From]) {
+ NumPaths += computeUniqueTailCallPath(TailCall, To, Path);
+ // Stop analyzing the remaining if we are already seeing more than one
+ // reachable paths.
+ if (NumPaths > 1)
+ break;
+ }
+ CurSearchingDepth--;
+ Visiting.erase(From);
+
+ // Undo already-computed path if it is not unique.
+ if (NumPaths != 1) {
+ Path.pop_back_n(Path.size() - Pos);
+ }
+
+ // Cache the result.
+ if (NumPaths == 1) {
+ UniquePaths[{From, To}].assign(Path.begin() + Pos, Path.end());
+#if LLVM_ENABLE_STATS
+ auto &LocalPath = UniquePaths[{From, To}];
+ assert((LocalPath.size() <= MaximumSearchDepth + 1) &&
+ "Path should not be longer than the maximum searching depth");
+ TailCallMaxTailCallPath = std::max(uint64_t(LocalPath.size()),
+ TailCallMaxTailCallPath.getValue());
+#endif
+ } else {
+ NonUniquePaths[{From, To}] = NumPaths;
+ }
+
+ return NumPaths;
+}
+
+uint64_t MissingFrameInferrer::computeUniqueTailCallPath(
+ uint64_t From, BinaryFunction *To, SmallVectorImpl<uint64_t> &Path) {
+ if (!TailCallEdgesF.count(From))
+ return 0;
+ Path.push_back(From);
+ uint64_t NumPaths = 0;
+ for (auto Target : TailCallEdgesF[From]) {
+ NumPaths += computeUniqueTailCallPath(Target, To, Path);
+ // Stop analyzing the remaining if we are already seeing more than one
+ // reachable paths.
+ if (NumPaths > 1)
+ break;
+ }
+
+ // Undo already-computed path if it is not unique.
+ if (NumPaths != 1)
+ Path.pop_back();
+ return NumPaths;
+}
+
+bool MissingFrameInferrer::inferMissingFrames(
+ uint64_t From, uint64_t To, SmallVectorImpl<uint64_t> &UniquePath) {
+ assert(!TailCallEdgesF.count(From) &&
+ "transition between From and To cannot be via a tailcall otherwise "
+ "they would not show up at the same time");
+ UniquePath.push_back(From);
+ uint64_t Pos = UniquePath.size();
+
+ FuncRange *ToFRange = Binary->findFuncRange(To);
+ if (!ToFRange)
+ return false;
+
+ // Bail out if caller has no known outgoing call edges.
+ if (!CallEdgesF.count(From))
+ return false;
+
+ // Done with the inference if the calle is reachable via a single callsite.
+ // This may not be accurate but it improves the search throughput.
+ for (auto Target : CallEdgesF[From]) {
+ if (Target == ToFRange->Func)
+ return true;
+ }
+
+ // Bail out if callee is not tailcall reachable at all.
+ if (!TailCallTargetFuncs.contains(ToFRange->Func))
+ return false;
+
+ Visiting.clear();
+ CurSearchingDepth = 0;
+ uint64_t NumPaths = 0;
+ for (auto Target : CallEdgesF[From]) {
+ NumPaths +=
+ computeUniqueTailCallPath(Target, ToFRange->Func, UniquePath);
+ // Stop analyzing the remaining if we are already seeing more than one
+ // reachable paths.
+ if (NumPaths > 1)
+ break;
+ }
+
+ // Undo already-computed path if it is not unique.
+ if (NumPaths != 1) {
+ UniquePath.pop_back_n(UniquePath.size() - Pos);
+ assert(UniquePath.back() == From && "broken path");
+ }
+
+#if LLVM_ENABLE_STATS
+ if (NumPaths == 1) {
+ if (ReachableViaUniquePaths.insert({From, ToFRange->StartAddress}).second)
+ TailCallUniReachable++;
+ } else if (NumPaths == 0) {
+ if (Unreachables.insert({From, ToFRange->StartAddress}).second) {
+ TailCallUnreachable++;
+ LLVM_DEBUG(dbgs() << "No path found from "
+ << format("%8" PRIx64 ":", From) << " to "
+ << format("%8" PRIx64 ":", ToFRange->StartAddress)
+ << "\n");
+ }
+ } else if (NumPaths > 1) {
+ if (ReachableViaMultiPaths.insert({From, ToFRange->StartAddress})
+ .second) {
+ TailCallMultiReachable++;
+ LLVM_DEBUG(dbgs() << "Multiple paths found from "
+ << format("%8" PRIx64 ":", From) << " to "
+ << format("%8" PRIx64 ":", ToFRange->StartAddress)
+ << "\n");
+ }
+ }
+#endif
+
+ return NumPaths == 1;
+}
+
+void MissingFrameInferrer::inferMissingFrames(
+ const SmallVectorImpl<uint64_t> &Context,
+ SmallVectorImpl<uint64_t> &NewContext) {
+ if (Context.size() == 1) {
+ NewContext = Context;
+ return;
+ }
+
+ NewContext.clear();
+ for (uint64_t I = 1; I < Context.size(); I++) {
+ inferMissingFrames(Context[I - 1], Context[I], NewContext);
+ }
+ NewContext.push_back(Context.back());
+
+ assert((NewContext.size() >= Context.size()) &&
+ "Inferred context should include all frames in the original context");
+ assert((NewContext.size() > Context.size() || NewContext == Context) &&
+ "Inferred context should be exactly the same "
+ "with the original context");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/MissingFrameInferrer.h b/src/llvm-project/llvm/tools/llvm-profgen/MissingFrameInferrer.h
new file mode 100644
index 0000000..4680a9a
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-profgen/MissingFrameInferrer.h
@@ -0,0 +1,116 @@
+//===-- MissingFrameInferrer.h - Missing frame inferrer ---------- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_PROFGEN_MISSINGFRAMEINFERRER_H
+#define LLVM_TOOLS_LLVM_PROFGEN_MISSINGFRAMEINFERRER_H
+
+#include "PerfReader.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include <unordered_map>
+#include <unordered_set>
+
+namespace llvm {
+namespace sampleprof {
+
+class ProfiledBinary;
+struct BinaryFunction;
+
+class MissingFrameInferrer {
+public:
+ MissingFrameInferrer(ProfiledBinary *Binary) : Binary(Binary) {}
+
+ // Defininig a frame transition from a caller function to the callee function.
+ using CallerCalleePair = std::pair<BinaryFunction *, BinaryFunction *>;
+
+ void initialize(const ContextSampleCounterMap *SampleCounters);
+
+ // Given an input `Context`, output `NewContext` with inferred missing tail
+ // call frames.
+ void inferMissingFrames(const SmallVectorImpl<uint64_t> &Context,
+ SmallVectorImpl<uint64_t> &NewContext);
+
+private:
+ friend class ProfiledBinary;
+
+ // Compute a unique tail call path for a pair of source frame address and
+ // target frame address. Append the unique path prefix (not including `To`) to
+ // `UniquePath` if exists. Return the whether this's a unqiue tail call
+ // path. The source/dest frame will typically be a pair of adjacent frame
+ // entries of call stack samples.
+ bool inferMissingFrames(uint64_t From, uint64_t To,
+ SmallVectorImpl<uint64_t> &UniquePath);
+
+ // Compute a unique tail call path from the source frame address to the target
+ // function. Output the unique path prefix (not including `To`) in
+ // `UniquePath` if exists. Return the number of possibly availabe tail call
+ // paths.
+ uint64_t computeUniqueTailCallPath(uint64_t From, BinaryFunction *To,
+ SmallVectorImpl<uint64_t> &UniquePath);
+
+ // Compute a unique tail call path from the source function to the target
+ // function. Output the unique path prefix (not including `To`) in
+ // `UniquePath` if exists. Return the number of possibly availabe tail call
+ // paths.
+ uint64_t computeUniqueTailCallPath(BinaryFunction *From, BinaryFunction *To,
+ SmallVectorImpl<uint64_t> &UniquePath);
+
+ ProfiledBinary *Binary;
+
+ // A map of call instructions to their target addresses. This is first
+ // populated with static call edges but then trimmed down to dynamic call
+ // edges based on LBR samples.
+ std::unordered_map<uint64_t, std::unordered_set<uint64_t>> CallEdges;
+
+ // A map of tail call instructions to their target addresses. This is first
+ // populated with static call edges but then trimmed down to dynamic call
+ // edges based on LBR samples.
+ std::unordered_map<uint64_t, std::unordered_set<uint64_t>> TailCallEdges;
+
+ // Dynamic call targets in terms of BinaryFunction for any calls.
+ std::unordered_map<uint64_t, std::unordered_set<BinaryFunction *>> CallEdgesF;
+
+ // Dynamic call targets in terms of BinaryFunction for tail calls.
+ std::unordered_map<uint64_t, std::unordered_set<BinaryFunction *>>
+ TailCallEdgesF;
+
+ // Dynamic tail call targets of caller functions.
+ std::unordered_map<BinaryFunction *, std::vector<uint64_t>> FuncToTailCallMap;
+
+ // Functions that are reachable via tail calls.
+ DenseSet<const BinaryFunction *> TailCallTargetFuncs;
+
+ struct PairHash {
+ std::size_t operator()(
+ const std::pair<BinaryFunction *, BinaryFunction *> &Pair) const {
+ return std::hash<BinaryFunction *>()(Pair.first) ^
+ std::hash<BinaryFunction *>()(Pair.second);
+ }
+ };
+
+ // Cached results from a CallerCalleePair to a unique call path between them.
+ std::unordered_map<CallerCalleePair, std::vector<uint64_t>, PairHash>
+ UniquePaths;
+ // Cached results from CallerCalleePair to the number of available call paths.
+ std::unordered_map<CallerCalleePair, uint64_t, PairHash> NonUniquePaths;
+
+ DenseSet<BinaryFunction *> Visiting;
+
+ uint32_t CurSearchingDepth = 0;
+
+#if LLVM_ENABLE_STATS
+ DenseSet<std::pair<uint64_t, uint64_t>> ReachableViaUniquePaths;
+ DenseSet<std::pair<uint64_t, uint64_t>> Unreachables;
+ DenseSet<std::pair<uint64_t, uint64_t>> ReachableViaMultiPaths;
+#endif
+};
+} // end namespace sampleprof
+} // end namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp
index f28a852..86c0131 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -96,8 +96,7 @@
return;
}
- if (!isValidFallThroughRange(Binary->virtualAddrToOffset(Target),
- Binary->virtualAddrToOffset(End), Binary)) {
+ if (!isValidFallThroughRange(Target, End, Binary)) {
// Skip unwinding the rest of LBR trace when a bogus range is seen.
State.setInvalid();
return;
@@ -186,17 +185,11 @@
return;
auto Ret = CtxCounterMap->emplace(Hashable<ContextKey>(Key), SampleCounter());
SampleCounter &SCounter = Ret.first->second;
- for (auto &Item : Cur->RangeSamples) {
- uint64_t StartOffset = Binary->virtualAddrToOffset(std::get<0>(Item));
- uint64_t EndOffset = Binary->virtualAddrToOffset(std::get<1>(Item));
- SCounter.recordRangeCount(StartOffset, EndOffset, std::get<2>(Item));
- }
+ for (auto &I : Cur->RangeSamples)
+ SCounter.recordRangeCount(std::get<0>(I), std::get<1>(I), std::get<2>(I));
- for (auto &Item : Cur->BranchSamples) {
- uint64_t SourceOffset = Binary->virtualAddrToOffset(std::get<0>(Item));
- uint64_t TargetOffset = Binary->virtualAddrToOffset(std::get<1>(Item));
- SCounter.recordBranchCount(SourceOffset, TargetOffset, std::get<2>(Item));
- }
+ for (auto &I : Cur->BranchSamples)
+ SCounter.recordBranchCount(std::get<0>(I), std::get<1>(I), std::get<2>(I));
}
template <typename T>
@@ -326,7 +319,7 @@
std::unique_ptr<PerfReaderBase>
PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
- Optional<uint32_t> PIDFilter) {
+ std::optional<uint32_t> PIDFilter) {
std::unique_ptr<PerfReaderBase> PerfReader;
if (PerfInput.Format == PerfFormat::UnsymbolizedProfile) {
@@ -357,8 +350,10 @@
return PerfReader;
}
-PerfInputFile PerfScriptReader::convertPerfDataToTrace(
- ProfiledBinary *Binary, PerfInputFile &File, Optional<uint32_t> PIDFilter) {
+PerfInputFile
+PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary,
+ PerfInputFile &File,
+ std::optional<uint32_t> PIDFilter) {
StringRef PerfData = File.InputFile;
// Run perf script to retrieve PIDs matching binary we're interested in.
auto PerfExecutable = sys::Process::FindInEnvPath("PATH", "perf");
@@ -367,13 +362,14 @@
}
std::string PerfPath = *PerfExecutable;
std::string PerfTraceFile = PerfData.str() + ".script.tmp";
+ std::string ErrorFile = PerfData.str() + ".script.err.tmp";
StringRef ScriptMMapArgs[] = {PerfPath, "script", "--show-mmap-events",
"-F", "comm,pid", "-i",
PerfData};
- Optional<StringRef> Redirects[] = {llvm::None, // Stdin
- StringRef(PerfTraceFile), // Stdout
- StringRef(PerfTraceFile)}; // Stderr
- sys::ExecuteAndWait(PerfPath, ScriptMMapArgs, llvm::None, Redirects);
+ std::optional<StringRef> Redirects[] = {std::nullopt, // Stdin
+ StringRef(PerfTraceFile), // Stdout
+ StringRef(ErrorFile)}; // Stderr
+ sys::ExecuteAndWait(PerfPath, ScriptMMapArgs, std::nullopt, Redirects);
// Collect the PIDs
TraceStream TraceIt(PerfTraceFile);
@@ -402,7 +398,7 @@
StringRef ScriptSampleArgs[] = {PerfPath, "script", "--show-mmap-events",
"-F", "ip,brstack", "--pid",
PIDs, "-i", PerfData};
- sys::ExecuteAndWait(PerfPath, ScriptSampleArgs, llvm::None, Redirects);
+ sys::ExecuteAndWait(PerfPath, ScriptSampleArgs, std::nullopt, Redirects);
return {PerfTraceFile, PerfFormat::PerfScript, PerfContent::UnknownContent};
}
@@ -434,7 +430,7 @@
} else {
// Verify segments are loaded consecutively.
const auto &Offsets = Binary->getTextSegmentOffsets();
- auto It = std::lower_bound(Offsets.begin(), Offsets.end(), Event.Offset);
+ auto It = llvm::lower_bound(Offsets, Event.Offset);
if (It != Offsets.end() && *It == Event.Offset) {
// The event is for loading a separate executable segment.
auto I = std::distance(Offsets.begin(), It);
@@ -466,10 +462,16 @@
for (uint32_t I = 0; I < CtxKey->Context.size(); I++) {
if (OContextStr.str().size())
OContextStr << " @ ";
+ uint64_t Address = CtxKey->Context[I];
+ if (UseOffset) {
+ if (UseLoadableSegmentAsBase)
+ Address -= Binary->getFirstLoadableAddress();
+ else
+ Address -= Binary->getPreferredBaseAddress();
+ }
OContextStr << "0x"
- << utohexstr(
- Binary->virtualAddrToOffset(CtxKey->Context[I]),
- /*LowerCase=*/true);
+ << utohexstr(Address,
+ /*LowerCase=*/true);
}
return OContextStr.str();
} else {
@@ -569,6 +571,9 @@
break;
}
+ // Canonicalize to use preferred load address as base address.
+ Src = Binary->canonicalizeVirtualAddress(Src);
+ Dst = Binary->canonicalizeVirtualAddress(Dst);
bool SrcIsInternal = Binary->addressIsCode(Src);
bool DstIsInternal = Binary->addressIsCode(Dst);
if (!SrcIsInternal)
@@ -604,6 +609,8 @@
return false;
}
TraceIt.advance();
+
+ FrameAddr = Binary->canonicalizeVirtualAddress(FrameAddr);
// Currently intermixed frame from different binaries is not supported.
if (!Binary->addressIsCode(FrameAddr)) {
if (CallStack.empty())
@@ -736,14 +743,14 @@
uint64_t Start = I.first.first;
uint64_t End = I.first.second;
- if (!UseOffset || (UseOffset && UseLoadableSegmentAsBase)) {
- Start = Binary->offsetToVirtualAddr(Start);
- End = Binary->offsetToVirtualAddr(End);
- }
-
- if (UseOffset && UseLoadableSegmentAsBase) {
- Start -= Binary->getFirstLoadableAddress();
- End -= Binary->getFirstLoadableAddress();
+ if (UseOffset) {
+ if (UseLoadableSegmentAsBase) {
+ Start -= Binary->getFirstLoadableAddress();
+ End -= Binary->getFirstLoadableAddress();
+ } else {
+ Start -= Binary->getPreferredBaseAddress();
+ End -= Binary->getPreferredBaseAddress();
+ }
}
OS.indent(Indent);
@@ -815,13 +822,14 @@
Range.second.getAsInteger(16, Target))
exitWithErrorForTraceLine(TraceIt);
- if (!UseOffset || (UseOffset && UseLoadableSegmentAsBase)) {
- uint64_t BaseAddr = 0;
- if (UseOffset && UseLoadableSegmentAsBase)
- BaseAddr = Binary->getFirstLoadableAddress();
-
- Source = Binary->virtualAddrToOffset(Source + BaseAddr);
- Target = Binary->virtualAddrToOffset(Target + BaseAddr);
+ if (UseOffset) {
+ if (UseLoadableSegmentAsBase) {
+ Source += Binary->getFirstLoadableAddress();
+ Target += Binary->getFirstLoadableAddress();
+ } else {
+ Source += Binary->getPreferredBaseAddress();
+ Target += Binary->getPreferredBaseAddress();
+ }
}
Counter[{Source, Target}] += Count;
@@ -859,25 +867,26 @@
void PerfScriptReader::computeCounterFromLBR(const PerfSample *Sample,
uint64_t Repeat) {
SampleCounter &Counter = SampleCounters.begin()->second;
- uint64_t EndOffeset = 0;
+ uint64_t EndAddress = 0;
for (const LBREntry &LBR : Sample->LBRStack) {
- uint64_t SourceOffset = Binary->virtualAddrToOffset(LBR.Source);
- uint64_t TargetOffset = Binary->virtualAddrToOffset(LBR.Target);
+ uint64_t SourceAddress = LBR.Source;
+ uint64_t TargetAddress = LBR.Target;
- // Record the branch if its sourceOffset is external. It can be the case an
+ // Record the branch if its SourceAddress is external. It can be the case an
// external source call an internal function, later this branch will be used
// to generate the function's head sample.
- if (Binary->offsetIsCode(TargetOffset)) {
- Counter.recordBranchCount(SourceOffset, TargetOffset, Repeat);
+ if (Binary->addressIsCode(TargetAddress)) {
+ Counter.recordBranchCount(SourceAddress, TargetAddress, Repeat);
}
// If this not the first LBR, update the range count between TO of current
// LBR and FROM of next LBR.
- uint64_t StartOffset = TargetOffset;
- if (Binary->offsetIsCode(StartOffset) && Binary->offsetIsCode(EndOffeset) &&
- isValidFallThroughRange(StartOffset, EndOffeset, Binary))
- Counter.recordRangeCount(StartOffset, EndOffeset, Repeat);
- EndOffeset = SourceOffset;
+ uint64_t StartAddress = TargetAddress;
+ if (Binary->addressIsCode(StartAddress) &&
+ Binary->addressIsCode(EndAddress) &&
+ isValidFallThroughRange(StartAddress, EndAddress, Binary))
+ Counter.recordRangeCount(StartAddress, EndAddress, Repeat);
+ EndAddress = SourceAddress;
}
}
@@ -950,8 +959,8 @@
SmallVector<StringRef, 6> Fields;
bool R = RegMmap2.match(Line, &Fields);
if (!R) {
- std::string ErrorMsg = "Cannot parse mmap event: " + Line.str() + " \n";
- exitWithError(ErrorMsg);
+ std::string WarningMsg = "Cannot parse mmap event: " + Line.str() + " \n";
+ WithColor::warning() << WarningMsg;
}
Fields[PID].getAsInteger(10, MMap.PID);
Fields[MMAPPED_ADDRESS].getAsInteger(0, MMap.Address);
@@ -1087,13 +1096,13 @@
for (const auto &Item : AggregatedSamples) {
const PerfSample *Sample = Item.first.getPtr();
uint64_t Count = Item.second;
- uint64_t EndOffeset = 0;
+ uint64_t EndAddress = 0;
for (const LBREntry &LBR : Sample->LBRStack) {
- uint64_t SourceOffset = Binary->virtualAddrToOffset(LBR.Source);
- uint64_t StartOffset = Binary->virtualAddrToOffset(LBR.Target);
- if (EndOffeset != 0)
- Ranges[{StartOffset, EndOffeset}] += Count;
- EndOffeset = SourceOffset;
+ uint64_t SourceAddress = LBR.Source;
+ uint64_t StartAddress = LBR.Target;
+ if (EndAddress != 0)
+ Ranges[{StartAddress, EndAddress}] += Count;
+ EndAddress = SourceAddress;
}
}
@@ -1102,17 +1111,14 @@
return;
}
- auto WarnInvalidRange =
- [&](uint64_t StartOffset, uint64_t EndOffset, StringRef Msg) {
- if (!ShowDetailedWarning)
- return;
- WithColor::warning()
- << "["
- << format("%8" PRIx64, Binary->offsetToVirtualAddr(StartOffset))
- << ","
- << format("%8" PRIx64, Binary->offsetToVirtualAddr(EndOffset))
- << "]: " << Msg << "\n";
- };
+ auto WarnInvalidRange = [&](uint64_t StartAddress, uint64_t EndAddress,
+ StringRef Msg) {
+ if (!ShowDetailedWarning)
+ return;
+ WithColor::warning() << "[" << format("%8" PRIx64, StartAddress) << ","
+ << format("%8" PRIx64, EndAddress) << "]: " << Msg
+ << "\n";
+ };
const char *EndNotBoundaryMsg = "Range is not on instruction boundary, "
"likely due to profile and binary mismatch.";
@@ -1130,31 +1136,37 @@
uint64_t BogusRange = 0;
for (auto &I : Ranges) {
- uint64_t StartOffset = I.first.first;
- uint64_t EndOffset = I.first.second;
+ uint64_t StartAddress = I.first.first;
+ uint64_t EndAddress = I.first.second;
TotalRangeNum += I.second;
- if (!Binary->offsetIsCode(StartOffset) ||
- !Binary->offsetIsTransfer(EndOffset)) {
+ if (!Binary->addressIsCode(StartAddress) &&
+ !Binary->addressIsCode(EndAddress))
+ continue;
+
+ if (!Binary->addressIsCode(StartAddress) ||
+ !Binary->addressIsTransfer(EndAddress)) {
InstNotBoundary += I.second;
- WarnInvalidRange(StartOffset, EndOffset, EndNotBoundaryMsg);
+ WarnInvalidRange(StartAddress, EndAddress, EndNotBoundaryMsg);
}
- auto *FRange = Binary->findFuncRangeForOffset(StartOffset);
+ auto *FRange = Binary->findFuncRange(StartAddress);
if (!FRange) {
UnmatchedRange += I.second;
- WarnInvalidRange(StartOffset, EndOffset, DanglingRangeMsg);
+ WarnInvalidRange(StartAddress, EndAddress, DanglingRangeMsg);
continue;
}
- if (EndOffset >= FRange->EndOffset) {
+ if (EndAddress >= FRange->EndAddress) {
RangeCrossFunc += I.second;
- WarnInvalidRange(StartOffset, EndOffset, RangeCrossFuncMsg);
+ WarnInvalidRange(StartAddress, EndAddress, RangeCrossFuncMsg);
}
- if (!isValidFallThroughRange(StartOffset, EndOffset, Binary)) {
+ if (Binary->addressIsCode(StartAddress) &&
+ Binary->addressIsCode(EndAddress) &&
+ !isValidFallThroughRange(StartAddress, EndAddress, Binary)) {
BogusRange += I.second;
- WarnInvalidRange(StartOffset, EndOffset, BogusRangeMsg);
+ WarnInvalidRange(StartAddress, EndAddress, BogusRangeMsg);
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h
index 3ffed99..14137e8 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/PerfReader.h
@@ -119,7 +119,7 @@
// only changes the leaf of frame stack. \fn isEqual is a virtual function,
// which will have perf overhead. In the future, if we redesign a better hash
// function, then we can just skip this or switch to non-virtual function(like
-// just ignore comparision if hash conflicts probabilities is low)
+// just ignore comparison if hash conflicts probabilities is low)
template <class T> class Hashable {
public:
std::shared_ptr<T> Data;
@@ -567,9 +567,9 @@
Binary->setBaseAddress(Binary->getPreferredBaseAddress());
};
virtual ~PerfReaderBase() = default;
- static std::unique_ptr<PerfReaderBase> create(ProfiledBinary *Binary,
- PerfInputFile &PerfInput,
- Optional<uint32_t> PIDFilter);
+ static std::unique_ptr<PerfReaderBase>
+ create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
+ std::optional<uint32_t> PIDFilter);
// Entry of the reader to parse multiple perf traces
virtual void parsePerfTraces() = 0;
@@ -594,15 +594,15 @@
class PerfScriptReader : public PerfReaderBase {
public:
PerfScriptReader(ProfiledBinary *B, StringRef PerfTrace,
- Optional<uint32_t> PID)
+ std::optional<uint32_t> PID)
: PerfReaderBase(B, PerfTrace), PIDFilter(PID){};
// Entry of the reader to parse multiple perf traces
void parsePerfTraces() override;
// Generate perf script from perf data
- static PerfInputFile convertPerfDataToTrace(ProfiledBinary *Binary,
- PerfInputFile &File,
- Optional<uint32_t> PIDFilter);
+ static PerfInputFile
+ convertPerfDataToTrace(ProfiledBinary *Binary, PerfInputFile &File,
+ std::optional<uint32_t> PIDFilter);
// Extract perf script type by peaking at the input
static PerfContent checkPerfScriptType(StringRef FileName);
@@ -663,7 +663,7 @@
// Keep track of all invalid return addresses
std::set<uint64_t> InvalidReturnAddresses;
// PID for the process of interest
- Optional<uint32_t> PIDFilter;
+ std::optional<uint32_t> PIDFilter;
};
/*
@@ -675,7 +675,7 @@
class LBRPerfReader : public PerfScriptReader {
public:
LBRPerfReader(ProfiledBinary *Binary, StringRef PerfTrace,
- Optional<uint32_t> PID)
+ std::optional<uint32_t> PID)
: PerfScriptReader(Binary, PerfTrace, PID){};
// Parse the LBR only sample.
void parseSample(TraceStream &TraceIt, uint64_t Count) override;
@@ -693,7 +693,7 @@
class HybridPerfReader : public PerfScriptReader {
public:
HybridPerfReader(ProfiledBinary *Binary, StringRef PerfTrace,
- Optional<uint32_t> PID)
+ std::optional<uint32_t> PID)
: PerfScriptReader(Binary, PerfTrace, PID){};
// Parse the hybrid sample including the call and LBR line
void parseSample(TraceStream &TraceIt, uint64_t Count) override;
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp
index 6acbb14..dfc42a5 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "ProfileGenerator.h"
#include "ErrorHandling.h"
+#include "MissingFrameInferrer.h"
#include "PerfReader.h"
#include "ProfiledBinary.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
@@ -32,8 +33,8 @@
clEnumValN(SPF_GCC, "gcc",
"GCC encoding (only meaningful for -sample)")));
-cl::opt<bool> UseMD5(
- "use-md5", cl::init(false), cl::Hidden,
+static cl::opt<bool> UseMD5(
+ "use-md5", cl::Hidden,
cl::desc("Use md5 to represent function names in the output profile (only "
"meaningful for -extbinary)"));
@@ -90,17 +91,23 @@
"Update total samples by accumulating all its body samples."),
llvm::cl::Optional);
-extern cl::opt<int> ProfileSummaryCutoffHot;
-extern cl::opt<bool> UseContextLessSummary;
-
static cl::opt<bool> GenCSNestedProfile(
"gen-cs-nested-profile", cl::Hidden, cl::init(true),
cl::desc("Generate nested function profiles for CSSPGO"));
+cl::opt<bool> InferMissingFrames(
+ "infer-missing-frames", llvm::cl::init(true),
+ llvm::cl::desc(
+ "Infer missing call frames due to compiler tail call elimination."),
+ llvm::cl::Optional);
+
using namespace llvm;
using namespace sampleprof;
namespace llvm {
+extern cl::opt<int> ProfileSummaryCutoffHot;
+extern cl::opt<bool> UseContextLessSummary;
+
namespace sampleprof {
// Initialize the MaxCompressionSize to -1 which means no size limit
@@ -420,25 +427,24 @@
// function.
for (const auto &CI : *SampleCounters) {
if (const auto *CtxKey = dyn_cast<AddrBasedCtxKey>(CI.first.getPtr())) {
- for (auto Addr : CtxKey->Context) {
- if (FuncRange *FRange = Binary->findFuncRangeForOffset(
- Binary->virtualAddrToOffset(Addr)))
+ for (auto StackAddr : CtxKey->Context) {
+ if (FuncRange *FRange = Binary->findFuncRange(StackAddr))
ProfiledFunctions.insert(FRange->Func);
}
}
for (auto Item : CI.second.RangeCounter) {
- uint64_t StartOffset = Item.first.first;
- if (FuncRange *FRange = Binary->findFuncRangeForOffset(StartOffset))
+ uint64_t StartAddress = Item.first.first;
+ if (FuncRange *FRange = Binary->findFuncRange(StartAddress))
ProfiledFunctions.insert(FRange->Func);
}
for (auto Item : CI.second.BranchCounter) {
- uint64_t SourceOffset = Item.first.first;
- uint64_t TargetOffset = Item.first.first;
- if (FuncRange *FRange = Binary->findFuncRangeForOffset(SourceOffset))
+ uint64_t SourceAddress = Item.first.first;
+ uint64_t TargetAddress = Item.first.second;
+ if (FuncRange *FRange = Binary->findFuncRange(SourceAddress))
ProfiledFunctions.insert(FRange->Func);
- if (FuncRange *FRange = Binary->findFuncRangeForOffset(TargetOffset))
+ if (FuncRange *FRange = Binary->findFuncRange(TargetAddress))
ProfiledFunctions.insert(FRange->Func);
}
}
@@ -565,16 +571,15 @@
void ProfileGenerator::populateBoundarySamplesWithProbesForAllFunctions(
const BranchSample &BranchCounters) {
for (const auto &Entry : BranchCounters) {
- uint64_t SourceOffset = Entry.first.first;
- uint64_t TargetOffset = Entry.first.second;
+ uint64_t SourceAddress = Entry.first.first;
+ uint64_t TargetAddress = Entry.first.second;
uint64_t Count = Entry.second;
assert(Count != 0 && "Unexpected zero weight branch");
- StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
+ StringRef CalleeName = getCalleeNameForAddress(TargetAddress);
if (CalleeName.size() == 0)
continue;
- uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset);
const MCDecodedPseudoProbe *CallProbe =
Binary->getCallProbeForAddr(SourceAddress);
if (CallProbe == nullptr)
@@ -644,8 +649,8 @@
// samples. This is to be consistent with compiler that interpret zero count
// as unexecuted(cold).
for (const auto &I : RangeCounter) {
- uint64_t StartOffset = I.first.first;
- for (const auto &Range : Binary->getRangesForOffset(StartOffset))
+ uint64_t StartAddress = I.first.first;
+ for (const auto &Range : Binary->getRanges(StartAddress))
Ranges[{Range.first, Range.second - 1}] += 0;
}
}
@@ -657,8 +662,8 @@
void ProfileGenerator::populateBodySamplesForAllFunctions(
const RangeSample &RangeCounter) {
for (const auto &Range : preprocessRangeCounter(RangeCounter)) {
- uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
- uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
+ uint64_t RangeBegin = Range.first.first;
+ uint64_t RangeEnd = Range.first.second;
uint64_t Count = Range.second;
InstructionPointer IP(Binary, RangeBegin, true);
@@ -669,16 +674,15 @@
continue;
do {
- uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
- const SampleContextFrameVector &FrameVec =
- Binary->getFrameLocationStack(Offset);
+ const SampleContextFrameVector FrameVec =
+ Binary->getFrameLocationStack(IP.Address);
if (!FrameVec.empty()) {
// FIXME: As accumulating total count per instruction caused some
// regression, we changed to accumulate total count per byte as a
// workaround. Tuning hotness threshold on the compiler side might be
// necessary in the future.
FunctionSamples &FunctionProfile = getLeafProfileAndAddTotalSamples(
- FrameVec, Count * Binary->getInstSize(Offset));
+ FrameVec, Count * Binary->getInstSize(IP.Address));
updateBodySamplesforFunctionProfile(FunctionProfile, FrameVec.back(),
Count);
}
@@ -686,9 +690,10 @@
}
}
-StringRef ProfileGeneratorBase::getCalleeNameForOffset(uint64_t TargetOffset) {
+StringRef
+ProfileGeneratorBase::getCalleeNameForAddress(uint64_t TargetAddress) {
// Get the function range by branch target if it's a call branch.
- auto *FRange = Binary->findFuncRangeForStartOffset(TargetOffset);
+ auto *FRange = Binary->findFuncRangeForStartAddr(TargetAddress);
// We won't accumulate sample count for a range whose start is not the real
// function entry such as outlined function or inner labels.
@@ -701,17 +706,17 @@
void ProfileGenerator::populateBoundarySamplesForAllFunctions(
const BranchSample &BranchCounters) {
for (const auto &Entry : BranchCounters) {
- uint64_t SourceOffset = Entry.first.first;
- uint64_t TargetOffset = Entry.first.second;
+ uint64_t SourceAddress = Entry.first.first;
+ uint64_t TargetAddress = Entry.first.second;
uint64_t Count = Entry.second;
assert(Count != 0 && "Unexpected zero weight branch");
- StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
+ StringRef CalleeName = getCalleeNameForAddress(TargetAddress);
if (CalleeName.size() == 0)
continue;
// Record called target sample and its count.
const SampleContextFrameVector &FrameVec =
- Binary->getFrameLocationStack(SourceOffset);
+ Binary->getCachedFrameLocationStack(SourceAddress);
if (!FrameVec.empty()) {
FunctionSamples &FunctionProfile =
getLeafProfileAndAddTotalSamples(FrameVec, 0);
@@ -771,8 +776,11 @@
collectProfiledFunctions();
- if (Binary->usePseudoProbes())
+ if (Binary->usePseudoProbes()) {
Binary->decodePseudoProbe();
+ if (InferMissingFrames)
+ initializeMissingFrameInferrer();
+ }
if (SampleCounters) {
if (Binary->usePseudoProbes()) {
@@ -788,8 +796,17 @@
postProcessProfiles();
}
+void CSProfileGenerator::initializeMissingFrameInferrer() {
+ Binary->getMissingContextInferrer()->initialize(SampleCounters);
+}
+
+void CSProfileGenerator::inferMissingFrames(
+ const SmallVectorImpl<uint64_t> &Context,
+ SmallVectorImpl<uint64_t> &NewContext) {
+ Binary->inferMissingFrames(Context, NewContext);
+}
+
void CSProfileGenerator::computeSizeForProfiledFunctions() {
- std::unordered_set<const BinaryFunction *> ProfiledFunctions;
for (auto *Func : Binary->getProfiledFunctions())
Binary->computeInlinedContextSizeForFunc(Func);
@@ -842,8 +859,8 @@
RangeSample Ranges;
findDisjointRanges(Ranges, RangeCounter);
for (const auto &Range : Ranges) {
- uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
- uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
+ uint64_t RangeBegin = Range.first.first;
+ uint64_t RangeEnd = Range.first.second;
uint64_t Count = Range.second;
// Disjoint ranges have introduce zero-filled gap that
// doesn't belong to current context, filter them out.
@@ -858,8 +875,7 @@
continue;
do {
- uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
- auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset);
+ auto LeafLoc = Binary->getInlineLeafFrameLoc(IP.Address);
if (LeafLoc) {
// Recording body sample for this specific context
updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count);
@@ -873,12 +889,12 @@
ContextTrieNode *Node, const BranchSample &BranchCounters) {
for (const auto &Entry : BranchCounters) {
- uint64_t SourceOffset = Entry.first.first;
- uint64_t TargetOffset = Entry.first.second;
+ uint64_t SourceAddress = Entry.first.first;
+ uint64_t TargetAddress = Entry.first.second;
uint64_t Count = Entry.second;
assert(Count != 0 && "Unexpected zero weight branch");
- StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
+ StringRef CalleeName = getCalleeNameForAddress(TargetAddress);
if (CalleeName.size() == 0)
continue;
@@ -886,7 +902,7 @@
LineLocation CalleeCallSite(0, 0);
if (CallerNode != &getRootContext()) {
// Record called target sample and its count
- auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceOffset);
+ auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceAddress);
if (LeafLoc) {
CallerNode->getFunctionSamples()->addCalledTargetSamples(
LeafLoc->Location.LineOffset,
@@ -1054,8 +1070,8 @@
}
for (const auto &Range : *PRanges) {
- uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
- uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
+ uint64_t RangeBegin = Range.first.first;
+ uint64_t RangeEnd = Range.first.second;
uint64_t Count = Range.second;
InstructionPointer IP(Binary, RangeBegin, true);
@@ -1078,13 +1094,13 @@
}
}
-static void
-extractPrefixContextStack(SampleContextFrameVector &ContextStack,
- const SmallVectorImpl<uint64_t> &Addresses,
- ProfiledBinary *Binary) {
+static void extractPrefixContextStack(SampleContextFrameVector &ContextStack,
+ const SmallVectorImpl<uint64_t> &AddrVec,
+ ProfiledBinary *Binary) {
SmallVector<const MCDecodedPseudoProbe *, 16> Probes;
- for (auto Addr : reverse(Addresses)) {
- const MCDecodedPseudoProbe *CallProbe = Binary->getCallProbeForAddr(Addr);
+ for (auto Address : reverse(AddrVec)) {
+ const MCDecodedPseudoProbe *CallProbe =
+ Binary->getCallProbeForAddr(Address);
// These could be the cases when a probe is not found at a calliste. Cutting
// off the context from here since the inliner will not know how to consume
// a context with unknown callsites.
@@ -1113,18 +1129,16 @@
for (const auto &CI : *SampleCounters) {
const AddrBasedCtxKey *CtxKey =
dyn_cast<AddrBasedCtxKey>(CI.first.getPtr());
- SampleContextFrameVector ContextStack;
- extractPrefixContextStack(ContextStack, CtxKey->Context, Binary);
// Fill in function body samples from probes, also infer caller's samples
// from callee's probe
- populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStack);
+ populateBodySamplesWithProbes(CI.second.RangeCounter, CtxKey);
// Fill in boundary samples for a call probe
- populateBoundarySamplesWithProbes(CI.second.BranchCounter, ContextStack);
+ populateBoundarySamplesWithProbes(CI.second.BranchCounter, CtxKey);
}
}
void CSProfileGenerator::populateBodySamplesWithProbes(
- const RangeSample &RangeCounter, SampleContextFrames ContextStack) {
+ const RangeSample &RangeCounter, const AddrBasedCtxKey *CtxKey) {
ProbeCounterMap ProbeCounter;
// Extract the top frame probes by looking up each address among the range in
// the Address2ProbeMap
@@ -1140,8 +1154,7 @@
if (!Probe->isBlock() || Count == 0)
continue;
- ContextTrieNode *ContextNode =
- getContextNodeForLeafProbe(ContextStack, Probe);
+ ContextTrieNode *ContextNode = getContextNodeForLeafProbe(CtxKey, Probe);
FunctionSamples &FunctionProfile = *ContextNode->getFunctionSamples();
// Record the current frame and FunctionProfile whenever samples are
// collected for non-danglie probes. This is for reporting all of the
@@ -1185,21 +1198,20 @@
}
void CSProfileGenerator::populateBoundarySamplesWithProbes(
- const BranchSample &BranchCounter, SampleContextFrames ContextStack) {
+ const BranchSample &BranchCounter, const AddrBasedCtxKey *CtxKey) {
for (const auto &BI : BranchCounter) {
- uint64_t SourceOffset = BI.first.first;
- uint64_t TargetOffset = BI.first.second;
+ uint64_t SourceAddress = BI.first.first;
+ uint64_t TargetAddress = BI.first.second;
uint64_t Count = BI.second;
- uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset);
const MCDecodedPseudoProbe *CallProbe =
Binary->getCallProbeForAddr(SourceAddress);
if (CallProbe == nullptr)
continue;
FunctionSamples &FunctionProfile =
- getFunctionProfileForLeafProbe(ContextStack, CallProbe);
+ getFunctionProfileForLeafProbe(CtxKey, CallProbe);
FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count);
FunctionProfile.addTotalSamples(Count);
- StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
+ StringRef CalleeName = getCalleeNameForAddress(TargetAddress);
if (CalleeName.size() == 0)
continue;
FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(), 0, CalleeName,
@@ -1208,7 +1220,23 @@
}
ContextTrieNode *CSProfileGenerator::getContextNodeForLeafProbe(
- SampleContextFrames ContextStack, const MCDecodedPseudoProbe *LeafProbe) {
+ const AddrBasedCtxKey *CtxKey, const MCDecodedPseudoProbe *LeafProbe) {
+
+ const SmallVectorImpl<uint64_t> *PContext = &CtxKey->Context;
+ SmallVector<uint64_t, 16> NewContext;
+
+ if (InferMissingFrames) {
+ SmallVector<uint64_t, 16> Context = CtxKey->Context;
+ // Append leaf frame for a complete inference.
+ Context.push_back(LeafProbe->getAddress());
+ inferMissingFrames(Context, NewContext);
+ // Pop out the leaf probe that was pushed in above.
+ NewContext.pop_back();
+ PContext = &NewContext;
+ }
+
+ SampleContextFrameVector ContextStack;
+ extractPrefixContextStack(ContextStack, *PContext, Binary);
// Explicitly copy the context for appending the leaf context
SampleContextFrameVector NewContextStack(ContextStack.begin(),
@@ -1234,9 +1262,8 @@
}
FunctionSamples &CSProfileGenerator::getFunctionProfileForLeafProbe(
- SampleContextFrames ContextStack, const MCDecodedPseudoProbe *LeafProbe) {
- return *getContextNodeForLeafProbe(ContextStack, LeafProbe)
- ->getFunctionSamples();
+ const AddrBasedCtxKey *CtxKey, const MCDecodedPseudoProbe *LeafProbe) {
+ return *getContextNodeForLeafProbe(CtxKey, LeafProbe)->getFunctionSamples();
}
} // end namespace sampleprof
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h
index 0ce4645..471792e 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfileGenerator.h
@@ -108,7 +108,7 @@
void updateCallsiteSamples();
- StringRef getCalleeNameForOffset(uint64_t TargetOffset);
+ StringRef getCalleeNameForAddress(uint64_t TargetAddress);
void computeSummaryAndThreshold(SampleProfileMap &ProfileMap);
@@ -334,18 +334,18 @@
// Fill in function body samples from probes
void populateBodySamplesWithProbes(const RangeSample &RangeCounter,
- SampleContextFrames ContextStack);
+ const AddrBasedCtxKey *CtxKey);
// Fill in boundary samples for a call probe
void populateBoundarySamplesWithProbes(const BranchSample &BranchCounter,
- SampleContextFrames ContextStack);
+ const AddrBasedCtxKey *CtxKey);
ContextTrieNode *
- getContextNodeForLeafProbe(SampleContextFrames ContextStack,
+ getContextNodeForLeafProbe(const AddrBasedCtxKey *CtxKey,
const MCDecodedPseudoProbe *LeafProbe);
// Helper function to get FunctionSamples for the leaf probe
FunctionSamples &
- getFunctionProfileForLeafProbe(SampleContextFrames ContextStack,
+ getFunctionProfileForLeafProbe(const AddrBasedCtxKey *CtxKey,
const MCDecodedPseudoProbe *LeafProbe);
void convertToProfileMap(ContextTrieNode &Node,
@@ -358,6 +358,13 @@
bool collectFunctionsFromLLVMProfile(
std::unordered_set<const BinaryFunction *> &ProfiledFunctions) override;
+ void initializeMissingFrameInferrer();
+
+ // Given an input `Context`, output `NewContext` with inferred missing tail
+ // call frames.
+ void inferMissingFrames(const SmallVectorImpl<uint64_t> &Context,
+ SmallVectorImpl<uint64_t> &NewContext);
+
ContextTrieNode &getRootContext() { return ContextTracker.getRootContext(); };
// The container for holding the FunctionSamples used by context trie.
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index eef5b8e..00e9d50 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -8,6 +8,7 @@
#include "ProfiledBinary.h"
#include "ErrorHandling.h"
+#include "MissingFrameInferrer.h"
#include "ProfileGenerator.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
@@ -15,8 +16,10 @@
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/TargetSelect.h"
+#include <optional>
#define DEBUG_TYPE "load-binary"
@@ -53,6 +56,7 @@
"names only. Only work with show-disassembly-only"));
extern cl::opt<bool> ShowDetailedWarning;
+extern cl::opt<bool> InferMissingFrames;
namespace llvm {
namespace sampleprof {
@@ -87,7 +91,7 @@
ContextTrieNode *CurrNode = &RootContext;
ContextTrieNode *PrevNode = nullptr;
- Optional<uint32_t> Size;
+ std::optional<uint32_t> Size;
// Start from top-level context-less function, traverse down the reverse
// context trie to find the best/longest match for given context, then
@@ -97,7 +101,7 @@
PrevNode = CurrNode;
CurrNode = CurrNode->getChildContext(CallSiteLoc, Node->getFuncName());
if (CurrNode && CurrNode->getFunctionSize())
- Size = CurrNode->getFunctionSize().value();
+ Size = *CurrNode->getFunctionSize();
CallSiteLoc = Node->getCallSiteLoc();
Node = Node->getParentContext();
}
@@ -111,12 +115,12 @@
while (!Size && CurrNode && !CurrNode->getAllChildContext().empty()) {
CurrNode = &CurrNode->getAllChildContext().begin()->second;
if (CurrNode->getFunctionSize())
- Size = CurrNode->getFunctionSize().value();
+ Size = *CurrNode->getFunctionSize();
}
}
assert(Size && "We should at least find one context size.");
- return Size.value();
+ return *Size;
}
void BinarySizeContextTracker::trackInlineesOptimizedAway(
@@ -158,6 +162,20 @@
ProbeContext.pop_back();
}
+ProfiledBinary::ProfiledBinary(const StringRef ExeBinPath,
+ const StringRef DebugBinPath)
+ : Path(ExeBinPath), DebugBinaryPath(DebugBinPath), ProEpilogTracker(this),
+ TrackFuncContextSize(EnableCSPreInliner && UseContextCostForPreInliner) {
+ // Point to executable binary if debug info binary is not specified.
+ SymbolizerPath = DebugBinPath.empty() ? ExeBinPath : DebugBinPath;
+ setupSymbolizer();
+ if (InferMissingFrames)
+ MissingContextInferrer = std::make_unique<MissingFrameInferrer>(this);
+ load();
+}
+
+ProfiledBinary::~ProfiledBinary() {}
+
void ProfiledBinary::warnNoFuncEntry() {
uint64_t NoFuncEntryNum = 0;
for (auto &F : BinaryFunctions) {
@@ -165,7 +183,7 @@
continue;
bool hasFuncEntry = false;
for (auto &R : F.second.Ranges) {
- if (FuncRange *FR = findFuncRangeForStartOffset(R.first)) {
+ if (FuncRange *FR = findFuncRangeForStartAddr(R.first)) {
if (FR->IsFuncEntry) {
hasFuncEntry = true;
break;
@@ -204,11 +222,6 @@
// Find the preferred load address for text sections.
setPreferredTextSegmentAddresses(Obj);
- checkPseudoProbe(Obj);
-
- if (ShowDisassemblyOnly)
- decodePseudoProbe(Obj);
-
// Load debug info of subprograms from DWARF section.
// If path of debug info binary is specified, use the debug info from it,
// otherwise use the debug info from the executable binary.
@@ -220,12 +233,23 @@
loadSymbolsFromDWARF(*cast<ObjectFile>(&ExeBinary));
}
+ DisassembleFunctionSet.insert(DisassembleFunctions.begin(),
+ DisassembleFunctions.end());
+
+ checkPseudoProbe(Obj);
+
+ if (UsePseudoProbes)
+ populateElfSymbolAddressList(Obj);
+
+ if (ShowDisassemblyOnly)
+ decodePseudoProbe(Obj);
+
// Disassemble the text sections.
disassemble(Obj);
// Use function start and return address to infer prolog and epilog
- ProEpilogTracker.inferPrologOffsets(StartOffset2FuncRangeMap);
- ProEpilogTracker.inferEpilogOffsets(RetOffsets);
+ ProEpilogTracker.inferPrologAddresses(StartAddrToFuncRangeMap);
+ ProEpilogTracker.inferEpilogAddresses(RetAddressSet);
warnNoFuncEntry();
@@ -233,10 +257,10 @@
}
bool ProfiledBinary::inlineContextEqual(uint64_t Address1, uint64_t Address2) {
- uint64_t Offset1 = virtualAddrToOffset(Address1);
- uint64_t Offset2 = virtualAddrToOffset(Address2);
- const SampleContextFrameVector &Context1 = getFrameLocationStack(Offset1);
- const SampleContextFrameVector &Context2 = getFrameLocationStack(Offset2);
+ const SampleContextFrameVector &Context1 =
+ getCachedFrameLocationStack(Address1);
+ const SampleContextFrameVector &Context2 =
+ getCachedFrameLocationStack(Address2);
if (Context1.size() != Context2.size())
return false;
if (Context1.empty())
@@ -255,9 +279,8 @@
return ContextVec;
// Process from frame root to leaf
for (auto Address : Stack) {
- uint64_t Offset = virtualAddrToOffset(Address);
const SampleContextFrameVector &ExpandedContext =
- getFrameLocationStack(Offset);
+ getCachedFrameLocationStack(Address);
// An instruction without a valid debug line will be ignored by sample
// processing
if (ExpandedContext.empty())
@@ -353,10 +376,31 @@
if (!UsePseudoProbes)
return;
- std::unordered_set<uint64_t> ProfiledGuids;
- if (!ShowDisassemblyOnly)
- for (auto *F : ProfiledFunctions)
- ProfiledGuids.insert(Function::getGUID(F->FuncName));
+ MCPseudoProbeDecoder::Uint64Set GuidFilter;
+ MCPseudoProbeDecoder::Uint64Map FuncStartAddresses;
+ if (ShowDisassemblyOnly) {
+ if (DisassembleFunctionSet.empty()) {
+ FuncStartAddresses = SymbolStartAddrs;
+ } else {
+ for (auto &F : DisassembleFunctionSet) {
+ auto GUID = Function::getGUID(F.first());
+ if (auto StartAddr = SymbolStartAddrs.lookup(GUID)) {
+ FuncStartAddresses[GUID] = StartAddr;
+ FuncRange &Range = StartAddrToFuncRangeMap[StartAddr];
+ GuidFilter.insert(Function::getGUID(Range.getFuncName()));
+ }
+ }
+ }
+ } else {
+ for (auto *F : ProfiledFunctions) {
+ GuidFilter.insert(Function::getGUID(F->FuncName));
+ for (auto &Range : F->Ranges) {
+ auto GUIDs = StartAddrToSymMap.equal_range(Range.first);
+ for (auto I = GUIDs.first; I != GUIDs.second; ++I)
+ FuncStartAddresses[I->second] = I->first;
+ }
+ }
+ }
StringRef FileName = Obj->getFileName();
for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
@@ -375,7 +419,7 @@
StringRef Contents = unwrapOrError(Section.getContents(), FileName);
if (!ProbeDecoder.buildAddress2ProbeMap(
reinterpret_cast<const uint8_t *>(Contents.data()),
- Contents.size(), ProfiledGuids))
+ Contents.size(), GuidFilter, FuncStartAddresses))
exitWithError("Pseudo Probe decoder fail in .pseudo_probe section");
}
}
@@ -402,10 +446,8 @@
decodePseudoProbe(Obj);
}
-void ProfiledBinary::setIsFuncEntry(uint64_t Offset, StringRef RangeSymName) {
- // Note that the start offset of each ELF section can be a non-function
- // symbol, we need to binary search for the start of a real function range.
- auto *FuncRange = findFuncRangeForOffset(Offset);
+void ProfiledBinary::setIsFuncEntry(FuncRange *FuncRange,
+ StringRef RangeSymName) {
// Skip external function symbol.
if (!FuncRange)
return;
@@ -421,15 +463,13 @@
SectionSymbolsTy &Symbols,
const SectionRef &Section) {
std::size_t SE = Symbols.size();
- uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress();
+ uint64_t SectionAddress = Section.getAddress();
uint64_t SectSize = Section.getSize();
- uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress();
- uint64_t NextStartOffset =
- (SI + 1 < SE) ? Symbols[SI + 1].Addr - getPreferredBaseAddress()
- : SectionOffset + SectSize;
- setIsFuncEntry(StartOffset,
- FunctionSamples::getCanonicalFnName(Symbols[SI].Name));
-
+ uint64_t StartAddress = Symbols[SI].Addr;
+ uint64_t NextStartAddress =
+ (SI + 1 < SE) ? Symbols[SI + 1].Addr : SectionAddress + SectSize;
+ FuncRange *FRange = findFuncRange(StartAddress);
+ setIsFuncEntry(FRange, FunctionSamples::getCanonicalFnName(Symbols[SI].Name));
StringRef SymbolName =
ShowCanonicalFnName
? FunctionSamples::getCanonicalFnName(Symbols[SI].Name)
@@ -446,36 +486,34 @@
<< format("%8" PRIx64, End) << "\n";
};
- uint64_t Offset = StartOffset;
- // Size of a consecutive invalid instruction range starting from Offset -1
+ uint64_t Address = StartAddress;
+ // Size of a consecutive invalid instruction range starting from Address -1
// backwards.
uint64_t InvalidInstLength = 0;
- while (Offset < NextStartOffset) {
+ while (Address < NextStartAddress) {
MCInst Inst;
uint64_t Size;
// Disassemble an instruction.
- bool Disassembled =
- DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset),
- Offset + getPreferredBaseAddress(), nulls());
+ bool Disassembled = DisAsm->getInstruction(
+ Inst, Size, Bytes.slice(Address - SectionAddress), Address, nulls());
if (Size == 0)
Size = 1;
if (ShowDisassembly) {
if (ShowPseudoProbe) {
- ProbeDecoder.printProbeForAddress(outs(),
- Offset + getPreferredBaseAddress());
+ ProbeDecoder.printProbeForAddress(outs(), Address);
}
- outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress());
+ outs() << format("%8" PRIx64 ":", Address);
size_t Start = outs().tell();
if (Disassembled)
- IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs());
+ IPrinter->printInst(&Inst, Address + Size, "", *STI.get(), outs());
else
outs() << "\t<unknown>";
if (ShowSourceLocations) {
unsigned Cur = outs().tell() - Start;
if (Cur < 40)
outs().indent(40 - Cur);
- InstructionPointer IP(this, Offset);
+ InstructionPointer IP(this, Address);
outs() << getReversedLocWithContext(
symbolize(IP, ShowCanonicalFnName, ShowPseudoProbe));
}
@@ -486,35 +524,72 @@
const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode());
// Record instruction size.
- Offset2InstSizeMap[Offset] = Size;
+ AddressToInstSizeMap[Address] = Size;
// Populate address maps.
- CodeAddrOffsets.push_back(Offset);
+ CodeAddressVec.push_back(Address);
if (MCDesc.isCall()) {
- CallOffsets.insert(Offset);
- UncondBranchOffsets.insert(Offset);
+ CallAddressSet.insert(Address);
+ UncondBranchAddrSet.insert(Address);
} else if (MCDesc.isReturn()) {
- RetOffsets.insert(Offset);
- UncondBranchOffsets.insert(Offset);
+ RetAddressSet.insert(Address);
+ UncondBranchAddrSet.insert(Address);
} else if (MCDesc.isBranch()) {
if (MCDesc.isUnconditionalBranch())
- UncondBranchOffsets.insert(Offset);
- BranchOffsets.insert(Offset);
+ UncondBranchAddrSet.insert(Address);
+ BranchAddressSet.insert(Address);
+ }
+
+ // Record potential call targets for tail frame inference later-on.
+ if (InferMissingFrames && FRange) {
+ uint64_t Target = 0;
+ MIA->evaluateBranch(Inst, Address, Size, Target);
+ if (MCDesc.isCall()) {
+ // Indirect call targets are unknown at this point. Recording the
+ // unknown target (zero) for further LBR-based refinement.
+ MissingContextInferrer->CallEdges[Address].insert(Target);
+ } else if (MCDesc.isUnconditionalBranch()) {
+ assert(Target &&
+ "target should be known for unconditional direct branch");
+ // Any inter-function unconditional jump is considered tail call at
+ // this point. This is not 100% accurate and could further be
+ // optimized based on some source annotation.
+ FuncRange *ToFRange = findFuncRange(Target);
+ if (ToFRange && ToFRange->Func != FRange->Func)
+ MissingContextInferrer->TailCallEdges[Address].insert(Target);
+ LLVM_DEBUG({
+ dbgs() << "Direct Tail call: " << format("%8" PRIx64 ":", Address);
+ IPrinter->printInst(&Inst, Address + Size, "", *STI.get(), dbgs());
+ dbgs() << "\n";
+ });
+ } else if (MCDesc.isIndirectBranch() && MCDesc.isBarrier()) {
+ // This is an indirect branch but not necessarily an indirect tail
+ // call. The isBarrier check is to filter out conditional branch.
+ // Similar with indirect call targets, recording the unknown target
+ // (zero) for further LBR-based refinement.
+ MissingContextInferrer->TailCallEdges[Address].insert(Target);
+ LLVM_DEBUG({
+ dbgs() << "Indirect Tail call: "
+ << format("%8" PRIx64 ":", Address);
+ IPrinter->printInst(&Inst, Address + Size, "", *STI.get(), dbgs());
+ dbgs() << "\n";
+ });
+ }
}
if (InvalidInstLength) {
- WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
+ WarnInvalidInsts(Address - InvalidInstLength, Address - 1);
InvalidInstLength = 0;
}
} else {
InvalidInstLength += Size;
}
- Offset += Size;
+ Address += Size;
}
if (InvalidInstLength)
- WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
+ WarnInvalidInsts(Address - InvalidInstLength, Address - 1);
if (ShowDisassembly)
outs() << "\n";
@@ -536,9 +611,11 @@
if (!AsmInfo)
exitWithError("no assembly info for target " + TripleName, FileName);
- SubtargetFeatures Features = Obj->getFeatures();
+ Expected<SubtargetFeatures> Features = Obj->getFeatures();
+ if (!Features)
+ exitWithError(Features.takeError(), FileName);
STI.reset(
- TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString()));
+ TheTarget->createMCSubtargetInfo(TripleName, "", Features->getString()));
if (!STI)
exitWithError("no subtarget info for target " + TripleName, FileName);
@@ -582,8 +659,6 @@
for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
stable_sort(SecSyms.second);
- DisassembleFunctionSet.insert(DisassembleFunctions.begin(),
- DisassembleFunctions.end());
assert((DisassembleFunctionSet.empty() || ShowDisassemblyOnly) &&
"Functions to disassemble should be only specified together with "
"--show-disassembly-only");
@@ -599,13 +674,13 @@
continue;
uint64_t ImageLoadAddr = getPreferredBaseAddress();
- uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr;
+ uint64_t SectionAddress = Section.getAddress() - ImageLoadAddr;
uint64_t SectSize = Section.getSize();
if (!SectSize)
continue;
// Register the text section.
- TextSections.insert({SectionOffset, SectSize});
+ TextSections.insert({SectionAddress, SectSize});
StringRef SectionName = unwrapOrError(Section.getName(), FileName);
@@ -657,6 +732,20 @@
}
}
+void ProfiledBinary::populateElfSymbolAddressList(
+ const ELFObjectFileBase *Obj) {
+ // Create a mapping from virtual address to symbol GUID and the other way
+ // around.
+ StringRef FileName = Obj->getFileName();
+ for (const SymbolRef &Symbol : Obj->symbols()) {
+ const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
+ const StringRef Name = unwrapOrError(Symbol.getName(), FileName);
+ uint64_t GUID = Function::getGUID(Name);
+ SymbolStartAddrs[GUID] = Addr;
+ StartAddrToSymMap.emplace(Addr, GUID);
+ }
+}
+
void ProfiledBinary::loadSymbolsFromDWARFUnit(DWARFUnit &CompilationUnit) {
for (const auto &DieInfo : CompilationUnit.dies()) {
llvm::DWARFDie Die(&CompilationUnit, &DieInfo);
@@ -685,30 +774,28 @@
Func.FuncName = Ret.first->first;
for (const auto &Range : Ranges) {
- uint64_t FuncStart = Range.LowPC;
- uint64_t FuncSize = Range.HighPC - FuncStart;
+ uint64_t StartAddress = Range.LowPC;
+ uint64_t EndAddress = Range.HighPC;
- if (FuncSize == 0 || FuncStart < getPreferredBaseAddress())
+ if (EndAddress <= StartAddress ||
+ StartAddress < getPreferredBaseAddress())
continue;
- uint64_t StartOffset = FuncStart - getPreferredBaseAddress();
- uint64_t EndOffset = Range.HighPC - getPreferredBaseAddress();
-
// We may want to know all ranges for one function. Here group the
// ranges and store them into BinaryFunction.
- Func.Ranges.emplace_back(StartOffset, EndOffset);
+ Func.Ranges.emplace_back(StartAddress, EndAddress);
- auto R = StartOffset2FuncRangeMap.emplace(StartOffset, FuncRange());
+ auto R = StartAddrToFuncRangeMap.emplace(StartAddress, FuncRange());
if (R.second) {
FuncRange &FRange = R.first->second;
FRange.Func = &Func;
- FRange.StartOffset = StartOffset;
- FRange.EndOffset = EndOffset;
+ FRange.StartAddress = StartAddress;
+ FRange.EndAddress = EndAddress;
} else {
WithColor::warning()
<< "Duplicated symbol start address at "
- << format("%8" PRIx64, StartOffset + getPreferredBaseAddress())
- << " " << R.first->second.getFuncName() << " and " << Name << "\n";
+ << format("%8" PRIx64, StartAddress) << " "
+ << R.first->second.getFuncName() << " and " << Name << "\n";
}
}
}
@@ -726,7 +813,7 @@
// Handles DWO sections that can either be in .o, .dwo or .dwp files.
for (const auto &CompilationUnit : DebugContext->compile_units()) {
DWARFUnit *const DwarfUnit = CompilationUnit.get();
- if (llvm::Optional<uint64_t> DWOId = DwarfUnit->getDWOId()) {
+ if (std::optional<uint64_t> DWOId = DwarfUnit->getDWOId()) {
DWARFUnit *DWOCU = DwarfUnit->getNonSkeletonUnitDIE(false).getDwarfUnit();
if (!DWOCU->isDWOUnit()) {
std::string DWOName = dwarf::toString(
@@ -749,7 +836,7 @@
void ProfiledBinary::populateSymbolListFromDWARF(
ProfileSymbolList &SymbolList) {
- for (auto &I : StartOffset2FuncRangeMap)
+ for (auto &I : StartAddrToFuncRangeMap)
SymbolList.add(I.second.getFuncName());
}
@@ -770,7 +857,7 @@
bool UseProbeDiscriminator) {
assert(this == IP.Binary &&
"Binary should only symbolize its own instruction");
- auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(),
+ auto Addr = object::SectionedAddress{IP.Address,
object::SectionedAddress::UndefSection};
DIInliningInfo InlineStack = unwrapOrError(
Symbolizer->symbolizeInlinedCode(SymbolizerPath.str(), Addr),
@@ -802,10 +889,8 @@
return CallStack;
}
-void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
- uint64_t EndOffset) {
- uint64_t RangeBegin = offsetToVirtualAddr(StartOffset);
- uint64_t RangeEnd = offsetToVirtualAddr(EndOffset);
+void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t RangeBegin,
+ uint64_t RangeEnd) {
InstructionPointer IP(this, RangeBegin, true);
if (IP.Address != RangeBegin)
@@ -816,11 +901,9 @@
return;
do {
- uint64_t Offset = virtualAddrToOffset(IP.Address);
- const SampleContextFrameVector &SymbolizedCallStack =
- getFrameLocationStack(Offset, UsePseudoProbes);
- uint64_t Size = Offset2InstSizeMap[Offset];
-
+ const SampleContextFrameVector SymbolizedCallStack =
+ getFrameLocationStack(IP.Address, UsePseudoProbes);
+ uint64_t Size = AddressToInstSizeMap[IP.Address];
// Record instruction size for the corresponding context
FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size);
@@ -846,6 +929,12 @@
}
}
+void ProfiledBinary::inferMissingFrames(
+ const SmallVectorImpl<uint64_t> &Context,
+ SmallVectorImpl<uint64_t> &NewContext) {
+ MissingContextInferrer->inferMissingFrames(Context, NewContext);
+}
+
InstructionPointer::InstructionPointer(const ProfiledBinary *Binary,
uint64_t Address, bool RoundToNext)
: Binary(Binary), Address(Address) {
@@ -853,7 +942,7 @@
if (RoundToNext) {
// we might get address which is not the code
// it should round to the next valid address
- if (Index >= Binary->getCodeOffsetsSize())
+ if (Index >= Binary->getCodeAddrVecSize())
this->Address = UINT64_MAX;
else
this->Address = Binary->getAddressforIndex(Index);
@@ -862,7 +951,7 @@
bool InstructionPointer::advance() {
Index++;
- if (Index >= Binary->getCodeOffsetsSize()) {
+ if (Index >= Binary->getCodeAddrVecSize()) {
Address = UINT64_MAX;
return false;
}
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h
index c099316..cdbaec7 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/src/llvm-project/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -11,7 +11,7 @@
#include "CallContext.h"
#include "ErrorHandling.h"
-#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -53,15 +53,12 @@
namespace sampleprof {
class ProfiledBinary;
+class MissingFrameInferrer;
struct InstructionPointer {
const ProfiledBinary *Binary;
- union {
- // Offset of the executable segment of the binary.
- uint64_t Offset = 0;
- // Also used as address in unwinder
- uint64_t Address;
- };
+ // Address of the executable segment of the binary.
+ uint64_t Address;
// Index to the sorted code address array of the binary.
uint64_t Index = 0;
InstructionPointer(const ProfiledBinary *Binary, uint64_t Address,
@@ -100,46 +97,47 @@
// Info about function range. A function can be split into multiple
// non-continuous ranges, each range corresponds to one FuncRange.
struct FuncRange {
- uint64_t StartOffset;
- // EndOffset is an exclusive bound.
- uint64_t EndOffset;
+ uint64_t StartAddress;
+ // EndAddress is an exclusive bound.
+ uint64_t EndAddress;
// Function the range belongs to
BinaryFunction *Func;
- // Whether the start offset is the real entry of the function.
+ // Whether the start address is the real entry of the function.
bool IsFuncEntry = false;
StringRef getFuncName() { return Func->FuncName; }
};
-// PrologEpilog offset tracker, used to filter out broken stack samples
+// PrologEpilog address tracker, used to filter out broken stack samples
// Currently we use a heuristic size (two) to infer prolog and epilog
// based on the start address and return address. In the future,
// we will switch to Dwarf CFI based tracker
struct PrologEpilogTracker {
- // A set of prolog and epilog offsets. Used by virtual unwinding.
+ // A set of prolog and epilog addresses. Used by virtual unwinding.
std::unordered_set<uint64_t> PrologEpilogSet;
ProfiledBinary *Binary;
PrologEpilogTracker(ProfiledBinary *Bin) : Binary(Bin){};
// Take the two addresses from the start of function as prolog
- void inferPrologOffsets(std::map<uint64_t, FuncRange> &FuncStartOffsetMap) {
- for (auto I : FuncStartOffsetMap) {
+ void
+ inferPrologAddresses(std::map<uint64_t, FuncRange> &FuncStartAddressMap) {
+ for (auto I : FuncStartAddressMap) {
PrologEpilogSet.insert(I.first);
InstructionPointer IP(Binary, I.first);
if (!IP.advance())
break;
- PrologEpilogSet.insert(IP.Offset);
+ PrologEpilogSet.insert(IP.Address);
}
}
// Take the last two addresses before the return address as epilog
- void inferEpilogOffsets(std::unordered_set<uint64_t> &RetAddrs) {
+ void inferEpilogAddresses(std::unordered_set<uint64_t> &RetAddrs) {
for (auto Addr : RetAddrs) {
PrologEpilogSet.insert(Addr);
InstructionPointer IP(Binary, Addr);
if (!IP.backward())
break;
- PrologEpilogSet.insert(IP.Offset);
+ PrologEpilogSet.insert(IP.Address);
}
}
};
@@ -169,8 +167,8 @@
using ProbeFrameStack = SmallVector<std::pair<StringRef, uint32_t>>;
void trackInlineesOptimizedAway(MCPseudoProbeDecoder &ProbeDecoder,
- MCDecodedPseudoProbeInlineTree &ProbeNode,
- ProbeFrameStack &Context);
+ MCDecodedPseudoProbeInlineTree &ProbeNode,
+ ProbeFrameStack &Context);
void dump() { RootContext.dumpTree(); }
@@ -183,7 +181,7 @@
ContextTrieNode RootContext;
};
-using OffsetRange = std::pair<uint64_t, uint64_t>;
+using AddressRange = std::pair<uint64_t, uint64_t>;
class ProfiledBinary {
// Absolute path of the executable binary.
@@ -221,32 +219,42 @@
// A list of binary functions that have samples.
std::unordered_set<const BinaryFunction *> ProfiledFunctions;
- // An ordered map of mapping function's start offset to function range
+ // GUID to Elf symbol start address map
+ DenseMap<uint64_t, uint64_t> SymbolStartAddrs;
+
+ // Start address to Elf symbol GUID map
+ std::unordered_multimap<uint64_t, uint64_t> StartAddrToSymMap;
+
+ // An ordered map of mapping function's start address to function range
// relevant info. Currently to determine if the offset of ELF is the start of
// a real function, we leverage the function range info from DWARF.
- std::map<uint64_t, FuncRange> StartOffset2FuncRangeMap;
+ std::map<uint64_t, FuncRange> StartAddrToFuncRangeMap;
- // Offset to context location map. Used to expand the context.
- std::unordered_map<uint64_t, SampleContextFrameVector> Offset2LocStackMap;
+ // Address to context location map. Used to expand the context.
+ std::unordered_map<uint64_t, SampleContextFrameVector> AddressToLocStackMap;
- // Offset to instruction size map. Also used for quick offset lookup.
- std::unordered_map<uint64_t, uint64_t> Offset2InstSizeMap;
+ // Address to instruction size map. Also used for quick Address lookup.
+ std::unordered_map<uint64_t, uint64_t> AddressToInstSizeMap;
- // An array of offsets of all instructions sorted in increasing order. The
+ // An array of Addresses of all instructions sorted in increasing order. The
// sorting is needed to fast advance to the next forward/backward instruction.
- std::vector<uint64_t> CodeAddrOffsets;
- // A set of call instruction offsets. Used by virtual unwinding.
- std::unordered_set<uint64_t> CallOffsets;
- // A set of return instruction offsets. Used by virtual unwinding.
- std::unordered_set<uint64_t> RetOffsets;
- // An ordered set of unconditional branch instruction offsets.
- std::set<uint64_t> UncondBranchOffsets;
- // A set of branch instruction offsets.
- std::unordered_set<uint64_t> BranchOffsets;
+ std::vector<uint64_t> CodeAddressVec;
+ // A set of call instruction addresses. Used by virtual unwinding.
+ std::unordered_set<uint64_t> CallAddressSet;
+ // A set of return instruction addresses. Used by virtual unwinding.
+ std::unordered_set<uint64_t> RetAddressSet;
+ // An ordered set of unconditional branch instruction addresses.
+ std::set<uint64_t> UncondBranchAddrSet;
+ // A set of branch instruction addresses.
+ std::unordered_set<uint64_t> BranchAddressSet;
// Estimate and track function prolog and epilog ranges.
PrologEpilogTracker ProEpilogTracker;
+ // Infer missing frames due to compiler optimizations such as tail call
+ // elimination.
+ std::unique_ptr<MissingFrameInferrer> MissingContextInferrer;
+
// Track function sizes under different context
BinarySizeContextTracker FuncSizeTracker;
@@ -281,7 +289,8 @@
void setPreferredTextSegmentAddresses(const ELFObjectFileBase *O);
template <class ELFT>
- void setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName);
+ void setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj,
+ StringRef FileName);
void checkPseudoProbe(const ELFObjectFileBase *Obj);
@@ -301,10 +310,13 @@
// Load debug info from DWARF unit.
void loadSymbolsFromDWARFUnit(DWARFUnit &CompilationUnit);
+ // Create elf symbol to its start address mapping.
+ void populateElfSymbolAddressList(const ELFObjectFileBase *O);
+
// A function may be spilt into multiple non-continuous address ranges. We use
- // this to set whether start offset of a function is the real entry of the
+ // this to set whether start a function range is the real entry of the
// function and also set false to the non-function label.
- void setIsFuncEntry(uint64_t Offset, StringRef RangeSymName);
+ void setIsFuncEntry(FuncRange *FRange, StringRef RangeSymName);
// Warn if no entry range exists in the function.
void warnNoFuncEntry();
@@ -329,31 +341,24 @@
void load();
public:
- ProfiledBinary(const StringRef ExeBinPath, const StringRef DebugBinPath)
- : Path(ExeBinPath), DebugBinaryPath(DebugBinPath), ProEpilogTracker(this),
- TrackFuncContextSize(EnableCSPreInliner &&
- UseContextCostForPreInliner) {
- // Point to executable binary if debug info binary is not specified.
- SymbolizerPath = DebugBinPath.empty() ? ExeBinPath : DebugBinPath;
- setupSymbolizer();
- load();
- }
+ ProfiledBinary(const StringRef ExeBinPath, const StringRef DebugBinPath);
+ ~ProfiledBinary();
void decodePseudoProbe();
- uint64_t virtualAddrToOffset(uint64_t VirtualAddress) const {
- return VirtualAddress - BaseAddress;
- }
- uint64_t offsetToVirtualAddr(uint64_t Offset) const {
- return Offset + BaseAddress;
- }
StringRef getPath() const { return Path; }
StringRef getName() const { return llvm::sys::path::filename(Path); }
uint64_t getBaseAddress() const { return BaseAddress; }
void setBaseAddress(uint64_t Address) { BaseAddress = Address; }
+ // Canonicalize to use preferred load address as base address.
+ uint64_t canonicalizeVirtualAddress(uint64_t Address) {
+ return Address - BaseAddress + getPreferredBaseAddress();
+ }
// Return the preferred load address for the first executable segment.
- uint64_t getPreferredBaseAddress() const { return PreferredTextSegmentAddresses[0]; }
+ uint64_t getPreferredBaseAddress() const {
+ return PreferredTextSegmentAddresses[0];
+ }
// Return the preferred load address for the first loadable segment.
uint64_t getFirstLoadableAddress() const { return FirstLoadableAddress; }
// Return the file offset for the first executable segment.
@@ -365,64 +370,54 @@
return TextSegmentOffsets;
}
- uint64_t getInstSize(uint64_t Offset) const {
- auto I = Offset2InstSizeMap.find(Offset);
- if (I == Offset2InstSizeMap.end())
+ uint64_t getInstSize(uint64_t Address) const {
+ auto I = AddressToInstSizeMap.find(Address);
+ if (I == AddressToInstSizeMap.end())
return 0;
return I->second;
}
- bool offsetIsCode(uint64_t Offset) const {
- return Offset2InstSizeMap.find(Offset) != Offset2InstSizeMap.end();
- }
bool addressIsCode(uint64_t Address) const {
- uint64_t Offset = virtualAddrToOffset(Address);
- return offsetIsCode(Offset);
- }
- bool addressIsCall(uint64_t Address) const {
- uint64_t Offset = virtualAddrToOffset(Address);
- return CallOffsets.count(Offset);
- }
- bool addressIsReturn(uint64_t Address) const {
- uint64_t Offset = virtualAddrToOffset(Address);
- return RetOffsets.count(Offset);
- }
- bool addressInPrologEpilog(uint64_t Address) const {
- uint64_t Offset = virtualAddrToOffset(Address);
- return ProEpilogTracker.PrologEpilogSet.count(Offset);
+ return AddressToInstSizeMap.find(Address) != AddressToInstSizeMap.end();
}
- bool offsetIsTransfer(uint64_t Offset) {
- return BranchOffsets.count(Offset) || RetOffsets.count(Offset) ||
- CallOffsets.count(Offset);
+ bool addressIsCall(uint64_t Address) const {
+ return CallAddressSet.count(Address);
+ }
+ bool addressIsReturn(uint64_t Address) const {
+ return RetAddressSet.count(Address);
+ }
+ bool addressInPrologEpilog(uint64_t Address) const {
+ return ProEpilogTracker.PrologEpilogSet.count(Address);
+ }
+
+ bool addressIsTransfer(uint64_t Address) {
+ return BranchAddressSet.count(Address) || RetAddressSet.count(Address) ||
+ CallAddressSet.count(Address);
}
bool rangeCrossUncondBranch(uint64_t Start, uint64_t End) {
if (Start >= End)
return false;
- auto R = UncondBranchOffsets.lower_bound(Start);
- return R != UncondBranchOffsets.end() && *R < End;
+ auto R = UncondBranchAddrSet.lower_bound(Start);
+ return R != UncondBranchAddrSet.end() && *R < End;
}
uint64_t getAddressforIndex(uint64_t Index) const {
- return offsetToVirtualAddr(CodeAddrOffsets[Index]);
+ return CodeAddressVec[Index];
}
- size_t getCodeOffsetsSize() const { return CodeAddrOffsets.size(); }
+ size_t getCodeAddrVecSize() const { return CodeAddressVec.size(); }
bool usePseudoProbes() const { return UsePseudoProbes; }
bool useFSDiscriminator() const { return UseFSDiscriminator; }
- // Get the index in CodeAddrOffsets for the address
+ // Get the index in CodeAddressVec for the address
// As we might get an address which is not the code
// here it would round to the next valid code address by
// using lower bound operation
- uint32_t getIndexForOffset(uint64_t Offset) const {
- auto Low = llvm::lower_bound(CodeAddrOffsets, Offset);
- return Low - CodeAddrOffsets.begin();
- }
uint32_t getIndexForAddr(uint64_t Address) const {
- uint64_t Offset = virtualAddrToOffset(Address);
- return getIndexForOffset(Offset);
+ auto Low = llvm::lower_bound(CodeAddressVec, Address);
+ return Low - CodeAddressVec.begin();
}
uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const {
@@ -435,29 +430,29 @@
return 0;
}
- FuncRange *findFuncRangeForStartOffset(uint64_t Offset) {
- auto I = StartOffset2FuncRangeMap.find(Offset);
- if (I == StartOffset2FuncRangeMap.end())
+ FuncRange *findFuncRangeForStartAddr(uint64_t Address) {
+ auto I = StartAddrToFuncRangeMap.find(Address);
+ if (I == StartAddrToFuncRangeMap.end())
return nullptr;
return &I->second;
}
- // Binary search the function range which includes the input offset.
- FuncRange *findFuncRangeForOffset(uint64_t Offset) {
- auto I = StartOffset2FuncRangeMap.upper_bound(Offset);
- if (I == StartOffset2FuncRangeMap.begin())
+ // Binary search the function range which includes the input address.
+ FuncRange *findFuncRange(uint64_t Address) {
+ auto I = StartAddrToFuncRangeMap.upper_bound(Address);
+ if (I == StartAddrToFuncRangeMap.begin())
return nullptr;
I--;
- if (Offset >= I->second.EndOffset)
+ if (Address >= I->second.EndAddress)
return nullptr;
return &I->second;
}
// Get all ranges of one function.
- RangesTy getRangesForOffset(uint64_t Offset) {
- auto *FRange = findFuncRangeForOffset(Offset);
+ RangesTy getRanges(uint64_t Address) {
+ auto *FRange = findFuncRange(Address);
// Ignore the range which falls into plt section or system lib.
if (!FRange)
return RangesTy();
@@ -489,21 +484,30 @@
return FuncSizeTracker.getFuncSizeForContext(ContextNode);
}
+ void inferMissingFrames(const SmallVectorImpl<uint64_t> &Context,
+ SmallVectorImpl<uint64_t> &NewContext);
+
// Load the symbols from debug table and populate into symbol list.
void populateSymbolListFromDWARF(ProfileSymbolList &SymbolList);
+ SampleContextFrameVector
+ getFrameLocationStack(uint64_t Address, bool UseProbeDiscriminator = false) {
+ InstructionPointer IP(this, Address);
+ return symbolize(IP, true, UseProbeDiscriminator);
+ }
+
const SampleContextFrameVector &
- getFrameLocationStack(uint64_t Offset, bool UseProbeDiscriminator = false) {
- auto I = Offset2LocStackMap.emplace(Offset, SampleContextFrameVector());
+ getCachedFrameLocationStack(uint64_t Address,
+ bool UseProbeDiscriminator = false) {
+ auto I = AddressToLocStackMap.emplace(Address, SampleContextFrameVector());
if (I.second) {
- InstructionPointer IP(this, Offset);
- I.first->second = symbolize(IP, true, UseProbeDiscriminator);
+ I.first->second = getFrameLocationStack(Address, UseProbeDiscriminator);
}
return I.first->second;
}
- Optional<SampleContextFrame> getInlineLeafFrameLoc(uint64_t Offset) {
- const auto &Stack = getFrameLocationStack(Offset);
+ std::optional<SampleContextFrame> getInlineLeafFrameLoc(uint64_t Address) {
+ const auto &Stack = getCachedFrameLocationStack(Address);
if (Stack.empty())
return {};
return Stack.back();
@@ -511,19 +515,23 @@
void flushSymbolizer() { Symbolizer.reset(); }
+ MissingFrameInferrer* getMissingContextInferrer() {
+ return MissingContextInferrer.get();
+ }
+
// Compare two addresses' inline context
bool inlineContextEqual(uint64_t Add1, uint64_t Add2);
// Get the full context of the current stack with inline context filled in.
- // It will search the disassembling info stored in Offset2LocStackMap. This is
- // used as the key of function sample map
+ // It will search the disassembling info stored in AddressToLocStackMap. This
+ // is used as the key of function sample map
SampleContextFrameVector
getExpandedContext(const SmallVectorImpl<uint64_t> &Stack,
bool &WasLeafInlined);
// Go through instructions among the given range and record its size for the
// inline context.
- void computeInlinedContextSizeForRange(uint64_t StartOffset,
- uint64_t EndOffset);
+ void computeInlinedContextSizeForRange(uint64_t StartAddress,
+ uint64_t EndAddress);
void computeInlinedContextSizeForFunc(const BinaryFunction *Func);
diff --git a/src/llvm-project/llvm/tools/llvm-profgen/llvm-profgen.cpp b/src/llvm-project/llvm/tools/llvm-profgen/llvm-profgen.cpp
index 8b12c2f..596882c 100644
--- a/src/llvm-project/llvm/tools/llvm-profgen/llvm-profgen.cpp
+++ b/src/llvm-project/llvm/tools/llvm-profgen/llvm-profgen.cpp
@@ -24,7 +24,6 @@
static cl::opt<std::string> PerfScriptFilename(
"perfscript", cl::value_desc("perfscript"),
- llvm::cl::MiscFlags::CommaSeparated,
cl::desc("Path of perf-script trace created by Linux perf tool with "
"`script` command(the raw perf.data should be profiled with -b)"),
cl::cat(ProfGenCategory));
@@ -32,7 +31,7 @@
cl::aliasopt(PerfScriptFilename));
static cl::opt<std::string> PerfDataFilename(
- "perfdata", cl::value_desc("perfdata"), llvm::cl::MiscFlags::CommaSeparated,
+ "perfdata", cl::value_desc("perfdata"),
cl::desc("Path of raw perf data created by Linux perf tool (it should be "
"profiled with -b)"),
cl::cat(ProfGenCategory));
@@ -41,7 +40,6 @@
static cl::opt<std::string> UnsymbolizedProfFilename(
"unsymbolized-profile", cl::value_desc("unsymbolized profile"),
- llvm::cl::MiscFlags::CommaSeparated,
cl::desc("Path of the unsymbolized profile created by "
"`llvm-profgen` with `--skip-symbolization`"),
cl::cat(ProfGenCategory));
@@ -80,11 +78,11 @@
// Allow the missing perfscript if we only use to show binary disassembly.
if (!ShowDisassemblyOnly) {
// Validate input profile is provided only once
- uint16_t HasPerfData = PerfDataFilename.getNumOccurrences();
- uint16_t HasPerfScript = PerfScriptFilename.getNumOccurrences();
- uint16_t HasUnsymbolizedProfile =
- UnsymbolizedProfFilename.getNumOccurrences();
- uint16_t HasSampleProfile = SampleProfFilename.getNumOccurrences();
+ bool HasPerfData = PerfDataFilename.getNumOccurrences() > 0;
+ bool HasPerfScript = PerfScriptFilename.getNumOccurrences() > 0;
+ bool HasUnsymbolizedProfile =
+ UnsymbolizedProfFilename.getNumOccurrences() > 0;
+ bool HasSampleProfile = SampleProfFilename.getNumOccurrences() > 0;
uint16_t S =
HasPerfData + HasPerfScript + HasUnsymbolizedProfile + HasSampleProfile;
if (S != 1) {
@@ -169,7 +167,7 @@
Generator->generateProfile();
Generator->write();
} else {
- Optional<uint32_t> PIDFilter;
+ std::optional<uint32_t> PIDFilter;
if (ProcessId.getNumOccurrences())
PIDFilter = ProcessId;
PerfInputFile PerfFile = getPerfInputFile();
diff --git a/src/llvm-project/llvm/tools/llvm-rc/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-rc/CMakeLists.txt
index 71b7994..9fddba8 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-rc/CMakeLists.txt
@@ -2,6 +2,7 @@
Object
Option
Support
+ TargetParser
)
set(LLVM_TARGET_DEFINITIONS Opts.td)
@@ -19,6 +20,9 @@
ResourceScriptParser.cpp
ResourceScriptStmt.cpp
ResourceScriptToken.cpp
+ DEPENDS
+ WindresOptsTableGen
+ GENERATE_DRIVER
)
add_llvm_tool_symlink(llvm-windres llvm-rc)
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h
index 0f3d593..7a92f84 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h
@@ -79,8 +79,8 @@
uint32_t Characteristics;
uint32_t VersionInfo;
- Optional<uint32_t> Style;
- Optional<uint32_t> ExStyle;
+ std::optional<uint32_t> Style;
+ std::optional<uint32_t> ExStyle;
StringRef Caption;
struct FontInfo {
uint32_t Size;
@@ -89,7 +89,7 @@
bool IsItalic;
uint32_t Charset;
};
- Optional<FontInfo> Font;
+ std::optional<FontInfo> Font;
IntOrString Class;
ObjectInfo()
@@ -103,7 +103,7 @@
using BundleKey = std::pair<uint16_t, uint16_t>;
// Each bundle is in fact an array of 16 strings.
struct Bundle {
- std::array<Optional<std::vector<StringRef>>, 16> Data;
+ std::array<std::optional<std::vector<StringRef>>, 16> Data;
ObjectInfo DeclTimeInfo;
uint16_t MemoryFlags;
Bundle(const ObjectInfo &Info, uint16_t Flags)
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp
index 7cb4d02..c1f00d3 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptParser.cpp
@@ -554,7 +554,7 @@
RETURN_IF_ERROR(consumeType(Kind::Comma));
IntOrString Class;
- Optional<IntWithNotMask> Style;
+ std::optional<IntWithNotMask> Style;
if (ClassUpper == "CONTROL") {
// CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
ASSIGN_OR_RETURN(ClassStr, readString());
@@ -577,12 +577,12 @@
}
}
- Optional<uint32_t> ExStyle;
+ std::optional<uint32_t> ExStyle;
if (consumeOptionalType(Kind::Comma)) {
ASSIGN_OR_RETURN(Val, readInt());
ExStyle = *Val;
}
- Optional<uint32_t> HelpID;
+ std::optional<uint32_t> HelpID;
if (consumeOptionalType(Kind::Comma)) {
ASSIGN_OR_RETURN(Val, readInt());
HelpID = *Val;
diff --git a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h
index 4b659f0..71f6a9d 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h
+++ b/src/llvm-project/llvm/tools/llvm-rc/ResourceScriptStmt.h
@@ -611,8 +611,8 @@
StringRef Type;
IntOrString Title;
uint32_t ID, X, Y, Width, Height;
- Optional<IntWithNotMask> Style;
- Optional<uint32_t> ExtStyle, HelpID;
+ std::optional<IntWithNotMask> Style;
+ std::optional<uint32_t> ExtStyle, HelpID;
IntOrString Class;
// Control classes as described in DLGITEMTEMPLATEEX documentation.
@@ -636,8 +636,9 @@
Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
- Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
- Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
+ std::optional<IntWithNotMask> ItemStyle,
+ std::optional<uint32_t> ExtItemStyle,
+ std::optional<uint32_t> CtlHelpID, IntOrString CtlClass)
: Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
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 312cc15..8864bbb 100644
--- a/src/llvm-project/llvm/tools/llvm-rc/llvm-rc.cpp
+++ b/src/llvm-project/llvm/tools/llvm-rc/llvm-rc.cpp
@@ -18,6 +18,7 @@
#include "ResourceScriptToken.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Object/WindowsResource.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -55,11 +56,15 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+namespace rc_opt {
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -70,10 +75,11 @@
#include "Opts.inc"
#undef OPTION
};
+} // namespace rc_opt
-class RcOptTable : public opt::OptTable {
+class RcOptTable : public opt::GenericOptTable {
public:
- RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {}
+ RcOptTable() : GenericOptTable(rc_opt::InfoTable, /* IgnoreCase = */ true) {}
};
enum Windres_ID {
@@ -85,25 +91,30 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const WINDRES_##NAME[] = VALUE;
+namespace windres_opt {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "WindresOpts.inc"
#undef PREFIX
-const opt::OptTable::Info WindresInfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- { \
- WINDRES_##PREFIX, NAME, HELPTEXT, \
- METAVAR, WINDRES_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, WINDRES_##GROUP, \
- WINDRES_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, WINDRES_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, WINDRES_##GROUP, \
+ WINDRES_##ALIAS, ALIASARGS, VALUES},
#include "WindresOpts.inc"
#undef OPTION
};
+} // namespace windres_opt
-class WindresOptTable : public opt::OptTable {
+class WindresOptTable : public opt::GenericOptTable {
public:
- WindresOptTable() : OptTable(WindresInfoTable, /* IgnoreCase = */ false) {}
+ WindresOptTable()
+ : GenericOptTable(windres_opt::InfoTable, /* IgnoreCase = */ false) {}
};
static ExitOnError ExitOnErr;
@@ -127,10 +138,12 @@
StringRef Parent = llvm::sys::path::parent_path(Argv0);
ErrorOr<std::string> Path = std::error_code();
std::string TargetClang = (Triple + "-clang").str();
+ std::string VersionedClang = ("clang-" + Twine(LLVM_VERSION_MAJOR)).str();
if (!Parent.empty()) {
// First look for the tool with all potential names in the specific
// directory of Argv0, if known
- for (const auto *Name : {TargetClang.c_str(), "clang", "clang-cl"}) {
+ for (const auto *Name :
+ {TargetClang.c_str(), VersionedClang.c_str(), "clang", "clang-cl"}) {
Path = sys::findProgramByName(Name, Parent);
if (Path)
return Path;
@@ -205,6 +218,7 @@
std::string OutputFile;
Format OutputFormat = Res;
+ bool IsWindres = false;
bool BeVerbose = false;
WriterParams Params;
bool AppendNull = false;
@@ -216,7 +230,7 @@
bool preprocess(StringRef Src, StringRef Dst, const RcOptions &Opts,
const char *Argv0) {
std::string Clang;
- if (Opts.PrintCmdAndExit) {
+ if (Opts.PrintCmdAndExit || !Opts.PreprocessCmd.empty()) {
Clang = "clang";
} else {
ErrorOr<std::string> ClangOrErr = findClang(Argv0, Opts.Triple);
@@ -225,9 +239,12 @@
} else {
errs() << "llvm-rc: Unable to find clang, skipping preprocessing."
<< "\n";
- errs() << "Pass -no-cpp to disable preprocessing. This will be an error "
- "in the future."
- << "\n";
+ StringRef OptionName =
+ Opts.IsWindres ? "--no-preprocess" : "-no-preprocess";
+ errs()
+ << "Pass " << OptionName
+ << " to disable preprocessing. This will be an error in the future."
+ << "\n";
return false;
}
}
@@ -256,7 +273,7 @@
}
// 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(Clang, Args);
+ int Res = sys::ExecuteAndWait(Args[0], Args);
if (Res) {
fatalError("llvm-rc: Preprocessing failed.");
}
@@ -352,6 +369,8 @@
unsigned MAI, MAC;
opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
+ Opts.IsWindres = true;
+
// The tool prints nothing when invoked with no command-line arguments.
if (InputArgs.hasArg(WINDRES_help)) {
T.printHelp(outs(), "windres [options] file...",
@@ -724,16 +743,16 @@
} // anonymous namespace
-int main(int Argc, const char **Argv) {
+int llvm_rc_main(int Argc, char **Argv) {
InitLLVM X(Argc, Argv);
ExitOnErr.setBanner("llvm-rc: ");
- const char **DashDash = std::find_if(
- Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; });
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash);
+ char **DashDash = std::find_if(Argv + 1, Argv + Argc,
+ [](StringRef Str) { return Str == "--"; });
+ ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, DashDash);
ArrayRef<const char *> FileArgsArr;
if (DashDash != Argv + Argc)
- FileArgsArr = makeArrayRef(DashDash + 1, Argv + Argc);
+ FileArgsArr = ArrayRef(DashDash + 1, Argv + Argc);
RcOptions Opts = getOptions(Argv[0], ArgsArr, FileArgsArr);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/src/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
index d641b17..5f3cc7d 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -91,7 +91,7 @@
{0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn},
{0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy},
};
- return makeArrayRef(Ring);
+ return ArrayRef(Ring);
}
inline void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes,
@@ -341,8 +341,9 @@
return Location + Place;
}
- ErrorOr<StringRef> FunctionAtAddress(uint64_t Address,
- Optional<unsigned> SectionIndex) const;
+ ErrorOr<StringRef>
+ FunctionAtAddress(uint64_t Address,
+ std::optional<unsigned> SectionIndex) const;
const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex,
off_t IndexTableOffset) const;
@@ -363,9 +364,8 @@
const size_t PrinterContext<ET>::IndexTableEntrySize = 8;
template <typename ET>
-ErrorOr<StringRef>
-PrinterContext<ET>::FunctionAtAddress(uint64_t Address,
- Optional<unsigned> SectionIndex) const {
+ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(
+ uint64_t Address, std::optional<unsigned> SectionIndex) const {
if (!Symtab)
return inconvertibleErrorCode();
auto StrTableOrErr = ELF.getStringTableForSymtab(*Symtab);
@@ -501,8 +501,8 @@
? PREL31(Word, EHT.sh_addr)
: PREL31(Word, EHT.sh_addr + TableEntryOffset);
SW.printHex("PersonalityRoutineAddress", Address);
- Optional<unsigned> SecIndex =
- IsRelocatable ? Optional<unsigned>(EHT.sh_link) : None;
+ std::optional<unsigned> SecIndex =
+ IsRelocatable ? std::optional<unsigned>(EHT.sh_link) : std::nullopt;
if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))
SW.printString("PersonalityRoutineName", *Name);
}
@@ -574,8 +574,8 @@
// their code sections via the sh_link field. For a non-relocatable ELF file
// the sh_link field is not reliable, because we have one .ARM.exidx section
// normally, but might have many code sections.
- Optional<unsigned> SecIndex =
- IsRelocatable ? Optional<unsigned>(IT->sh_link) : None;
+ std::optional<unsigned> SecIndex =
+ IsRelocatable ? std::optional<unsigned>(IT->sh_link) : std::nullopt;
if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))
SW.printString("FunctionName", *Name);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
index b7cbf35..ef77d4b 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -143,35 +143,36 @@
{ 0xff, 0xff, 1, &Decoder::opcode_11111111 }, // UOP_END
};
-
// Unwind opcodes for ARM64.
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
const Decoder::RingEntry Decoder::Ring64[] = {
- { 0xe0, 0x00, 1, &Decoder::opcode_alloc_s },
- { 0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x },
- { 0xc0, 0x40, 1, &Decoder::opcode_save_fplr },
- { 0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x },
- { 0xf8, 0xc0, 2, &Decoder::opcode_alloc_m },
- { 0xfc, 0xc8, 2, &Decoder::opcode_save_regp },
- { 0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x },
- { 0xfc, 0xd0, 2, &Decoder::opcode_save_reg },
- { 0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x },
- { 0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair },
- { 0xfe, 0xd8, 2, &Decoder::opcode_save_fregp },
- { 0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x },
- { 0xfe, 0xdc, 2, &Decoder::opcode_save_freg },
- { 0xff, 0xde, 2, &Decoder::opcode_save_freg_x },
- { 0xff, 0xe0, 4, &Decoder::opcode_alloc_l },
- { 0xff, 0xe1, 1, &Decoder::opcode_setfp },
- { 0xff, 0xe2, 2, &Decoder::opcode_addfp },
- { 0xff, 0xe3, 1, &Decoder::opcode_nop },
- { 0xff, 0xe4, 1, &Decoder::opcode_end },
- { 0xff, 0xe5, 1, &Decoder::opcode_end_c },
- { 0xff, 0xe6, 1, &Decoder::opcode_save_next },
- { 0xff, 0xe8, 1, &Decoder::opcode_trap_frame },
- { 0xff, 0xe9, 1, &Decoder::opcode_machine_frame },
- { 0xff, 0xea, 1, &Decoder::opcode_context },
- { 0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call },
+ {0xe0, 0x00, 1, &Decoder::opcode_alloc_s},
+ {0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x},
+ {0xc0, 0x40, 1, &Decoder::opcode_save_fplr},
+ {0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x},
+ {0xf8, 0xc0, 2, &Decoder::opcode_alloc_m},
+ {0xfc, 0xc8, 2, &Decoder::opcode_save_regp},
+ {0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x},
+ {0xfc, 0xd0, 2, &Decoder::opcode_save_reg},
+ {0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x},
+ {0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair},
+ {0xfe, 0xd8, 2, &Decoder::opcode_save_fregp},
+ {0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x},
+ {0xfe, 0xdc, 2, &Decoder::opcode_save_freg},
+ {0xff, 0xde, 2, &Decoder::opcode_save_freg_x},
+ {0xff, 0xe0, 4, &Decoder::opcode_alloc_l},
+ {0xff, 0xe1, 1, &Decoder::opcode_setfp},
+ {0xff, 0xe2, 2, &Decoder::opcode_addfp},
+ {0xff, 0xe3, 1, &Decoder::opcode_nop},
+ {0xff, 0xe4, 1, &Decoder::opcode_end},
+ {0xff, 0xe5, 1, &Decoder::opcode_end_c},
+ {0xff, 0xe6, 1, &Decoder::opcode_save_next},
+ {0xff, 0xe7, 3, &Decoder::opcode_save_any_reg},
+ {0xff, 0xe8, 1, &Decoder::opcode_trap_frame},
+ {0xff, 0xe9, 1, &Decoder::opcode_machine_frame},
+ {0xff, 0xea, 1, &Decoder::opcode_context},
+ {0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call},
+ {0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr},
};
static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First,
@@ -855,7 +856,7 @@
bool Prologue) {
SW.startLine() << format("0x%02x ; end_c\n", OC[Offset]);
++Offset;
- return true;
+ return false;
}
bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset,
@@ -869,6 +870,83 @@
return false;
}
+bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ // Whether the instruction has writeback
+ bool Writeback = (OC[Offset + 1] & 0x20) == 0x20;
+ // Whether the instruction is paired. (Paired instructions are required
+ // to save/restore adjacent registers.)
+ bool Paired = (OC[Offset + 1] & 0x40) == 0x40;
+ // The kind of register saved:
+ // - 0 is an x register
+ // - 1 is the low half of a q register
+ // - 2 is a whole q register
+ int RegKind = (OC[Offset + 2] & 0xC0) >> 6;
+ // Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.)
+ int Reg = OC[Offset + 1] & 0x1F;
+ // Encoded stack offset of load/store instruction; decoding varies by mode.
+ int StackOffset = OC[Offset + 2] & 0x3F;
+ if (Writeback)
+ StackOffset++;
+ if (!Writeback && !Paired && RegKind != 2)
+ StackOffset *= 8;
+ else
+ StackOffset *= 16;
+
+ SW.startLine() << format("0x%02x%02x%02x ; ", OC[Offset],
+ OC[Offset + 1], OC[Offset + 2]);
+
+ // Verify the encoding is in a form we understand. The high bit of the first
+ // byte, and mode 3 for the register kind are apparently reserved. The
+ // encoded register must refer to a valid register.
+ int MaxReg = 0x1F;
+ if (Paired)
+ --MaxReg;
+ if (RegKind == 0)
+ --MaxReg;
+ if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) {
+ SW.getOStream() << "invalid save_any_reg encoding\n";
+ Offset += 3;
+ return false;
+ }
+
+ if (Paired) {
+ if (Prologue)
+ SW.getOStream() << "stp ";
+ else
+ SW.getOStream() << "ldp ";
+ } else {
+ if (Prologue)
+ SW.getOStream() << "str ";
+ else
+ SW.getOStream() << "ldr ";
+ }
+
+ char RegChar = 'x';
+ if (RegKind == 1) {
+ RegChar = 'd';
+ } else if (RegKind == 2) {
+ RegChar = 'q';
+ }
+
+ if (Paired)
+ SW.getOStream() << format("%c%d, %c%d, ", RegChar, Reg, RegChar, Reg + 1);
+ else
+ SW.getOStream() << format("%c%d, ", RegChar, Reg);
+
+ if (Writeback) {
+ if (Prologue)
+ SW.getOStream() << format("[sp, #-%d]!\n", StackOffset);
+ else
+ SW.getOStream() << format("[sp], #%d\n", StackOffset);
+ } else {
+ SW.getOStream() << format("[sp, #%d]\n", StackOffset);
+ }
+
+ Offset += 3;
+ return false;
+}
+
bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]);
@@ -899,6 +977,16 @@
return false;
}
+bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ if (Prologue)
+ SW.startLine() << format("0x%02x ; pacibsp\n", OC[Offset]);
+ else
+ SW.startLine() << format("0x%02x ; autibsp\n", OC[Offset]);
+ ++Offset;
+ return false;
+}
+
void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
bool Prologue) {
assert((!Prologue || Offset == 0) && "prologue should always use offset 0");
@@ -906,8 +994,8 @@
bool Terminated = false;
for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) {
for (unsigned DI = 0;; ++DI) {
- if ((isAArch64 && (DI >= array_lengthof(Ring64))) ||
- (!isAArch64 && (DI >= array_lengthof(Ring)))) {
+ if ((isAArch64 && (DI >= std::size(Ring64))) ||
+ (!isAArch64 && (DI >= std::size(Ring)))) {
SW.startLine() << format("0x%02x ; Bad opcode!\n",
Opcodes.data()[OI]);
++OI;
@@ -1160,7 +1248,7 @@
}
if (RF.C()) {
// Count the number of registers pushed below R11
- int FpOffset = 4 * countPopulation(GPRMask & ((1U << 11) - 1));
+ int FpOffset = 4 * llvm::popcount(GPRMask & ((1U << 11) - 1));
if (FpOffset)
SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n";
else
@@ -1256,7 +1344,7 @@
int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf;
int LocSZ = (RF.FrameSize() << 4) - SavSZ;
- if (RF.CR() == 3) {
+ if (RF.CR() == 2 || RF.CR() == 3) {
SW.startLine() << "mov x29, sp\n";
if (LocSZ <= 512) {
SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ);
@@ -1267,7 +1355,7 @@
if (LocSZ > 4080) {
SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080);
SW.startLine() << "sub sp, sp, #4080\n";
- } else if ((RF.CR() != 3 && LocSZ > 0) || LocSZ > 512) {
+ } else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) {
SW.startLine() << format("sub sp, sp, #%d\n", LocSZ);
}
if (RF.H()) {
@@ -1329,6 +1417,11 @@
19 + 2 * I + 1, 16 * I);
}
}
+ // CR=2 is yet undocumented, see
+ // https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream
+ // progress on getting it documented.
+ if (RF.CR() == 2)
+ SW.startLine() << "pacibsp\n";
SW.startLine() << "end\n";
return true;
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
index ceaa866..0ffebe5 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -121,6 +121,8 @@
bool Prologue);
bool opcode_save_next(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
+ bool opcode_save_any_reg(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
bool opcode_trap_frame(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
bool opcode_machine_frame(const uint8_t *Opcodes, unsigned &Offset,
@@ -129,6 +131,8 @@
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,
+ unsigned Length, bool Prologue);
void decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
bool Prologue);
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-readobj/CMakeLists.txt
index 9d2d888..e31e7a0 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-readobj/CMakeLists.txt
@@ -6,6 +6,7 @@
BinaryFormat
Option
Support
+ TargetParser
DebugInfoCodeView
DebugInfoMSF
DebugInfoPDB
@@ -27,6 +28,9 @@
Win64EHDumper.cpp
WindowsResourceDumper.cpp
XCOFFDumper.cpp
+ DEPENDS
+ ReadobjOptsTableGen
+ GENERATE_DRIVER
)
add_llvm_tool_symlink(llvm-readelf llvm-readobj)
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp
index caeb49a..5279e58 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -193,7 +193,6 @@
CPUType CompilationCPUType = CPUType::X64;
ScopedPrinter &Writer;
- BinaryByteStream TypeContents;
LazyRandomTypeCollection Types;
};
@@ -344,6 +343,7 @@
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64EC ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ),
@@ -578,6 +578,52 @@
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
};
+const EnumEntry<uint32_t> PELoadConfigGuardFlags[] = {
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CF_INSTRUMENTED),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CFW_INSTRUMENTED),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CF_FUNCTION_TABLE_PRESENT),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, SECURITY_COOKIE_UNUSED),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, PROTECT_DELAYLOAD_IAT),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ DELAYLOAD_IAT_IN_ITS_OWN_SECTION),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_EXPORT_SUPPRESSION_INFO_PRESENT),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CF_ENABLE_EXPORT_SUPPRESSION),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CF_LONGJUMP_TABLE_PRESENT),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ EH_CONTINUATION_TABLE_PRESENT),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_5BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_6BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_7BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_8BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_9BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_10BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_11BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_12BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_13BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_14BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_15BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_16BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_17BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_18BYTES),
+ LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
+ CF_FUNCTION_TABLE_SIZE_19BYTES),
+};
+
template <typename T>
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
COFFSymbolRef Symbol,
@@ -621,16 +667,15 @@
{
DictScope D(W, "ImageFileHeader");
- W.printEnum ("Machine", Obj->getMachine(),
- makeArrayRef(ImageFileMachineType));
+ W.printEnum("Machine", Obj->getMachine(), ArrayRef(ImageFileMachineType));
W.printNumber("SectionCount", Obj->getNumberOfSections());
W.printHex ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp());
W.printHex ("PointerToSymbolTable", Obj->getPointerToSymbolTable());
W.printNumber("SymbolCount", Obj->getNumberOfSymbols());
W.printNumber("StringTableSize", Obj->getStringTableSize());
W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader());
- W.printFlags ("Characteristics", Obj->getCharacteristics(),
- makeArrayRef(ImageFileCharacteristics));
+ W.printFlags("Characteristics", Obj->getCharacteristics(),
+ ArrayRef(ImageFileCharacteristics));
}
// Print PE header. This header does not exist if this is an object file and
@@ -691,9 +736,10 @@
W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion);
W.printNumber("SizeOfImage", Hdr->SizeOfImage);
W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
- W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
- W.printFlags ("Characteristics", Hdr->DLLCharacteristics,
- makeArrayRef(PEDLLCharacteristics));
+ W.printHex ("CheckSum", Hdr->CheckSum);
+ W.printEnum("Subsystem", Hdr->Subsystem, ArrayRef(PEWindowsSubsystem));
+ W.printFlags("Characteristics", Hdr->DLLCharacteristics,
+ ArrayRef(PEDLLCharacteristics));
W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
@@ -710,7 +756,7 @@
};
for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i)
- if (i < sizeof(directory) / sizeof(char *))
+ if (i < std::size(directory))
printDataDirectory(i, directory[i]);
else
printDataDirectory(i, "Unknown");
@@ -728,7 +774,7 @@
W.printHex("TimeDateStamp", FormattedTime, D.TimeDateStamp);
W.printHex("MajorVersion", D.MajorVersion);
W.printHex("MinorVersion", D.MinorVersion);
- W.printEnum("Type", D.Type, makeArrayRef(ImageDebugType));
+ W.printEnum("Type", D.Type, ArrayRef(ImageDebugType));
W.printHex("SizeOfData", D.SizeOfData);
W.printHex("AddressOfRawData", D.AddressOfRawData);
W.printHex("PointerToRawData", D.PointerToRawData);
@@ -745,7 +791,7 @@
DictScope PDBScope(W, "PDBInfo");
W.printHex("PDBSignature", DebugInfo->Signature.CVSignature);
if (DebugInfo->Signature.CVSignature == OMF::Signature::PDB70) {
- W.printBinary("PDBGUID", makeArrayRef(DebugInfo->PDB70.Signature));
+ W.printBinary("PDBGUID", ArrayRef(DebugInfo->PDB70.Signature));
W.printNumber("PDBAge", DebugInfo->PDB70.Age);
W.printString("PDBFileName", PDBFileName);
}
@@ -761,7 +807,7 @@
// but that might change in the future
uint16_t Characteristics = RawData[0];
W.printFlags("ExtendedCharacteristics", Characteristics,
- makeArrayRef(PEExtendedDLLCharacteristics));
+ ArrayRef(PEExtendedDLLCharacteristics));
}
W.printBinaryBlock("RawData", RawData);
}
@@ -807,11 +853,18 @@
if (Tables.GuardFidTableVA) {
ListScope LS(W, "GuardFidTable");
- if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags))
- printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5,
+ if (uint32_t Size =
+ Tables.GuardFlags &
+ uint32_t(COFF::GuardFlags::CF_FUNCTION_TABLE_SIZE_MASK)) {
+ // The size mask gives the number of extra bytes in addition to the 4-byte
+ // RVA of each entry in the table. As of writing only a 1-byte extra flag
+ // has been defined.
+ Size = (Size >> 28) + 4;
+ printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, Size,
PrintGuardFlags);
- else
+ } else {
printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4);
+ }
}
if (Tables.GuardIatTableVA) {
@@ -881,7 +934,8 @@
W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch);
W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable);
W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount);
- W.printHex("GuardFlags", Conf->GuardFlags);
+ W.printFlags("GuardFlags", Conf->GuardFlags, ArrayRef(PELoadConfigGuardFlags),
+ (uint32_t)COFF::GuardFlags::CF_FUNCTION_TABLE_SIZE_MASK);
Tables.GuardFidTableVA = Conf->GuardCFFunctionTable;
Tables.GuardFidTableCount = Conf->GuardCFFunctionCount;
@@ -1026,7 +1080,7 @@
W.printHex("IgnoredSubsectionKind", SubType);
SubType &= ~SubsectionIgnoreFlag;
}
- W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes));
+ W.printEnum("SubSectionType", SubType, ArrayRef(SubSectionTypes));
W.printHex("SubSectionSize", SubSectionSize);
// Get the contents of the subsection.
@@ -1123,7 +1177,7 @@
W.printHex("MaxStackSize", FD.MaxStackSize);
W.printHex("PrologSize", FD.PrologSize);
W.printHex("SavedRegsSize", FD.SavedRegsSize);
- W.printFlags("Flags", FD.Flags, makeArrayRef(FrameDataFlags));
+ W.printFlags("Flags", FD.Flags, ArrayRef(FrameDataFlags));
// The FrameFunc string is a small RPN program. It can be broken up into
// statements that end in the '=' operator, which assigns the value on
@@ -1241,7 +1295,7 @@
W.printHex("Filename", Filename, FC.FileNameOffset);
W.printHex("ChecksumSize", FC.Checksum.size());
W.printEnum("ChecksumKind", uint8_t(FC.Kind),
- makeArrayRef(FileChecksumKindNames));
+ ArrayRef(FileChecksumKindNames));
W.printBinary("ChecksumBytes", FC.Checksum);
}
@@ -1316,17 +1370,17 @@
Obj->getFileName());
}
SmallVector<TypeIndex, 128> SourceToDest;
- Optional<uint32_t> PCHSignature;
+ std::optional<PCHMergerInfo> PCHInfo;
if (GHash) {
std::vector<GloballyHashedType> Hashes =
GloballyHashedType::hashTypes(Types);
if (Error E =
mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest,
- Types, Hashes, PCHSignature))
+ Types, Hashes, PCHInfo))
return reportError(std::move(E), Obj->getFileName());
} else {
if (Error E = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
- PCHSignature))
+ PCHInfo))
return reportError(std::move(E), Obj->getFileName());
}
}
@@ -1380,9 +1434,9 @@
W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers);
W.printNumber("RelocationCount", Section->NumberOfRelocations);
W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
- W.printFlags ("Characteristics", Section->Characteristics,
- makeArrayRef(ImageSectionCharacteristics),
- COFF::SectionCharacteristics(0x00F00000));
+ W.printFlags("Characteristics", Section->Characteristics,
+ ArrayRef(ImageSectionCharacteristics),
+ COFF::SectionCharacteristics(0x00F00000));
if (opts::SectionRelocations) {
ListScope D(W, "Relocations");
@@ -1518,11 +1572,10 @@
W.printString("Name", SymbolName);
W.printNumber("Value", Symbol.getValue());
W.printNumber("Section", SectionName, Symbol.getSectionNumber());
- W.printEnum ("BaseType", Symbol.getBaseType(), makeArrayRef(ImageSymType));
- W.printEnum ("ComplexType", Symbol.getComplexType(),
- makeArrayRef(ImageSymDType));
- W.printEnum ("StorageClass", Symbol.getStorageClass(),
- makeArrayRef(ImageSymClass));
+ W.printEnum("BaseType", Symbol.getBaseType(), ArrayRef(ImageSymType));
+ W.printEnum("ComplexType", Symbol.getComplexType(), ArrayRef(ImageSymDType));
+ W.printEnum("StorageClass", Symbol.getStorageClass(),
+ ArrayRef(ImageSymClass));
W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols());
for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) {
@@ -1544,8 +1597,8 @@
DictScope AS(W, "AuxWeakExternal");
W.printNumber("Linked", getSymbolName(Aux->TagIndex), Aux->TagIndex);
- W.printEnum ("Search", Aux->Characteristics,
- makeArrayRef(WeakExternalCharacteristics));
+ W.printEnum("Search", Aux->Characteristics,
+ ArrayRef(WeakExternalCharacteristics));
} else if (Symbol.isFileRecord()) {
const char *FileName;
@@ -1570,7 +1623,7 @@
W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
W.printHex("Checksum", Aux->CheckSum);
W.printNumber("Number", AuxNumber);
- W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
+ W.printEnum("Selection", Aux->Selection, ArrayRef(ImageCOMDATSelect));
if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
&& Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
@@ -1616,16 +1669,17 @@
break;
}
case COFF::IMAGE_FILE_MACHINE_ARM64:
+ case COFF::IMAGE_FILE_MACHINE_ARM64EC:
case COFF::IMAGE_FILE_MACHINE_ARMNT: {
- ARM::WinEH::Decoder Decoder(W, Obj->getMachine() ==
- COFF::IMAGE_FILE_MACHINE_ARM64);
+ ARM::WinEH::Decoder Decoder(W, Obj->getMachine() !=
+ COFF::IMAGE_FILE_MACHINE_ARMNT);
// TODO Propagate the error.
consumeError(Decoder.dumpProcedureData(*Obj));
break;
}
default:
W.printEnum("unsupported Image Machine", Obj->getMachine(),
- makeArrayRef(ImageFileMachineType));
+ ArrayRef(ImageFileMachineType));
break;
}
}
@@ -1733,18 +1787,29 @@
DictScope Export(W, "Export");
StringRef Name;
- uint32_t Ordinal, RVA;
+ uint32_t Ordinal;
+ bool IsForwarder;
if (Error E = Exp.getSymbolName(Name))
reportError(std::move(E), Obj->getFileName());
if (Error E = Exp.getOrdinal(Ordinal))
reportError(std::move(E), Obj->getFileName());
- if (Error E = Exp.getExportRVA(RVA))
+ if (Error E = Exp.isForwarder(IsForwarder))
reportError(std::move(E), Obj->getFileName());
W.printNumber("Ordinal", Ordinal);
W.printString("Name", Name);
- W.printHex("RVA", RVA);
+ StringRef ForwardTo;
+ if (IsForwarder) {
+ if (Error E = Exp.getForwardTo(ForwardTo))
+ reportError(std::move(E), Obj->getFileName());
+ W.printString("ForwardedTo", ForwardTo);
+ } else {
+ uint32_t RVA;
+ if (Error E = Exp.getExportRVA(RVA))
+ reportError(std::move(E), Obj->getFileName());
+ W.printHex("RVA", RVA);
+ }
}
}
@@ -1862,7 +1927,7 @@
std::copy(RawEntryNameString.begin(), RawEntryNameString.end(),
EndianCorrectedNameString.begin() + 1);
EndianCorrectedNameString[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
- RawEntryNameString = makeArrayRef(EndianCorrectedNameString);
+ RawEntryNameString = ArrayRef(EndianCorrectedNameString);
}
std::string EntryNameString;
if (!llvm::convertUTF16ToUTF8String(RawEntryNameString, EntryNameString))
@@ -2074,6 +2139,6 @@
W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks);
W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill);
W.printFlags("Characteristics", TlsTable->Characteristics,
- makeArrayRef(ImageSectionCharacteristics),
+ ArrayRef(ImageSectionCharacteristics),
COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
}
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
index 5dc947e..365a598 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
@@ -226,8 +226,9 @@
W.getOStream() << "\n";
W.startLine() << "Program:\n";
W.indent();
- Entry.cfis().dump(W.getOStream(), DIDumpOptions(), nullptr,
- W.getIndentLevel());
+ auto DumpOpts = DIDumpOptions();
+ DumpOpts.IsEH = true;
+ Entry.cfis().dump(W.getOStream(), DumpOpts, W.getIndentLevel());
W.unindent();
W.unindent();
W.getOStream() << "\n";
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp
index ba7bae9..45fff0c 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/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -67,6 +66,7 @@
#include <cstdlib>
#include <iterator>
#include <memory>
+#include <optional>
#include <string>
#include <system_error>
#include <vector>
@@ -201,7 +201,7 @@
uint32_t Symbol;
typename ELFT::uint Offset;
typename ELFT::uint Info;
- Optional<int64_t> Addend;
+ std::optional<int64_t> Addend;
};
template <class ELFT> class MipsGOTParser;
@@ -289,7 +289,7 @@
bool NonVisibilityBitsUsed) const {};
virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable, bool IsDynamic,
+ std::optional<StringRef> StrTable, bool IsDynamic,
bool NonVisibilityBitsUsed) const = 0;
virtual void printMipsABIFlags() = 0;
@@ -305,13 +305,12 @@
// Returns the function symbol index for the given address. Matches the
// symbol's section with FunctionSec when specified.
- // Returns None if no function symbol can be found for the address or in case
- // it is not defined in the specified section.
- SmallVector<uint32_t>
- getSymbolIndexesForFunctionAddress(uint64_t SymValue,
- Optional<const Elf_Shdr *> FunctionSec);
+ // Returns std::nullopt if no function symbol can be found for the address or
+ // in case it is not defined in the specified section.
+ SmallVector<uint32_t> getSymbolIndexesForFunctionAddress(
+ uint64_t SymValue, std::optional<const Elf_Shdr *> FunctionSec);
bool printFunctionStackSize(uint64_t SymValue,
- Optional<const Elf_Shdr *> FunctionSec,
+ std::optional<const Elf_Shdr *> FunctionSec,
const Elf_Shdr &StackSizeSec, DataExtractor Data,
uint64_t *Offset);
void printStackSize(const Relocation<ELFT> &R, const Elf_Shdr &RelocSec,
@@ -355,13 +354,13 @@
Expected<StringRef> getSymbolVersion(const Elf_Sym &Sym,
bool &IsDefault) const;
- Expected<SmallVector<Optional<VersionEntry>, 0> *> getVersionMap() const;
+ Expected<SmallVector<std::optional<VersionEntry>, 0> *> getVersionMap() const;
DynRegionInfo DynRelRegion;
DynRegionInfo DynRelaRegion;
DynRegionInfo DynRelrRegion;
DynRegionInfo DynPLTRelRegion;
- Optional<DynRegionInfo> DynSymRegion;
+ std::optional<DynRegionInfo> DynSymRegion;
DynRegionInfo DynSymTabShndxRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
@@ -371,8 +370,8 @@
const Elf_Shdr *DotDynsymSec = nullptr;
const Elf_Shdr *DotAddrsigSec = nullptr;
DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
- Optional<uint64_t> SONameOffset;
- Optional<DenseMap<uint64_t, std::vector<uint32_t>>> AddressToIndexMap;
+ std::optional<uint64_t> SONameOffset;
+ std::optional<DenseMap<uint64_t, std::vector<uint32_t>>> AddressToIndexMap;
const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version
const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r
@@ -380,7 +379,7 @@
std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable,
+ std::optional<StringRef> StrTable,
bool IsDynamic) const;
Expected<unsigned>
getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex,
@@ -399,7 +398,7 @@
ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const;
private:
- mutable SmallVector<Optional<VersionEntry>, 0> VersionMap;
+ mutable SmallVector<std::optional<VersionEntry>, 0> VersionMap;
};
template <class ELFT>
@@ -493,7 +492,7 @@
template <class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
- Optional<StringRef> StrTable;
+ std::optional<StringRef> StrTable;
size_t Entries = 0;
Elf_Sym_Range Syms(nullptr, nullptr);
const Elf_Shdr *SymtabSec = IsDynamic ? DotDynsymSec : DotSymtabSec;
@@ -635,7 +634,7 @@
const RelSymbol<ELFT> &RelSym) override;
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable, bool IsDynamic,
+ std::optional<StringRef> StrTable, bool IsDynamic,
bool NonVisibilityBitsUsed) const override;
void printDynamicRelocHeader(unsigned Type, StringRef Name,
const DynRegionInfo &Reg) override;
@@ -692,7 +691,7 @@
DataRegion<Elf_Word> ShndxTable) const;
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable, bool IsDynamic,
+ std::optional<StringRef> StrTable, bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) const override;
void printProgramHeaders() override;
void printSectionMapping() override {}
@@ -759,14 +758,14 @@
} // end namespace llvm
template <class ELFT>
-Expected<SmallVector<Optional<VersionEntry>, 0> *>
+Expected<SmallVector<std::optional<VersionEntry>, 0> *>
ELFDumper<ELFT>::getVersionMap() const {
// If the VersionMap has already been loaded or if there is no dynamic symtab
// or version table, there is nothing to do.
if (!VersionMap.empty() || !DynSymRegion || !SymbolVersionSection)
return &VersionMap;
- Expected<SmallVector<Optional<VersionEntry>, 0>> MapOrErr =
+ Expected<SmallVector<std::optional<VersionEntry>, 0>> MapOrErr =
Obj.loadVersionMap(SymbolVersionNeedSection, SymbolVersionDefSection);
if (MapOrErr)
VersionMap = *MapOrErr;
@@ -804,7 +803,7 @@
return "";
}
- Expected<SmallVector<Optional<VersionEntry>, 0> *> MapOrErr =
+ Expected<SmallVector<std::optional<VersionEntry>, 0> *> MapOrErr =
getVersionMap();
if (!MapOrErr)
return MapOrErr.takeError();
@@ -881,11 +880,9 @@
}
template <typename ELFT>
-std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
- unsigned SymIndex,
- DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable,
- bool IsDynamic) const {
+std::string ELFDumper<ELFT>::getFullSymbolName(
+ const Elf_Sym &Symbol, unsigned SymIndex, DataRegion<Elf_Word> ShndxTable,
+ std::optional<StringRef> StrTable, bool IsDynamic) const {
if (!StrTable)
return "<?>";
@@ -940,7 +937,8 @@
if (Ndx != SHN_UNDEF && Ndx < SHN_LORESERVE)
return Ndx;
- auto CreateErr = [&](const Twine &Name, Optional<unsigned> Offset = None) {
+ auto CreateErr = [&](const Twine &Name,
+ std::optional<unsigned> Offset = std::nullopt) {
std::string Desc;
if (Offset)
Desc = (Name + "+0x" + Twine::utohexstr(*Offset)).str();
@@ -1411,6 +1409,7 @@
LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO);
LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_PROPERTY);
+ 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_BOOTDATA);
@@ -1649,14 +1648,18 @@
};
const EnumEntry<unsigned> ElfHeaderLoongArchFlags[] = {
- ENUM_ENT(EF_LOONGARCH_BASE_ABI_ILP32S, "ILP32, SOFT-FLOAT"),
- ENUM_ENT(EF_LOONGARCH_BASE_ABI_ILP32F, "ILP32, SINGLE-FLOAT"),
- ENUM_ENT(EF_LOONGARCH_BASE_ABI_ILP32D, "ILP32, DOUBLE-FLOAT"),
- ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64S, "LP64, SOFT-FLOAT"),
- ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64F, "LP64, SINGLE-FLOAT"),
- ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64D, "LP64, DOUBLE-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_ABI_SOFT_FLOAT, "SOFT-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_ABI_SINGLE_FLOAT, "SINGLE-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_ABI_DOUBLE_FLOAT, "DOUBLE-FLOAT"),
+ ENUM_ENT(EF_LOONGARCH_OBJABI_V0, "OBJ-v0"),
+ ENUM_ENT(EF_LOONGARCH_OBJABI_V1, "OBJ-v1"),
};
+static const EnumEntry<unsigned> ElfHeaderXtensaFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_MACH_NONE),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_XT_INSN),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_XT_LIT)
+};
const EnumEntry<unsigned> ElfSymOtherFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL),
@@ -1946,7 +1949,7 @@
const char *StringTableBegin = nullptr;
uint64_t StringTableSize = 0;
- Optional<DynRegionInfo> DynSymFromTable;
+ std::optional<DynRegionInfo> DynSymFromTable;
for (const Elf_Dyn &Dyn : dynamic_table()) {
switch (Dyn.d_tag) {
case ELF::DT_HASH:
@@ -2314,7 +2317,7 @@
case DT_MIPS_XHASH:
return FormatHexValue(Value);
case DT_MIPS_FLAGS:
- return FormatFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags));
+ return FormatFlags(Value, ArrayRef(ElfDynamicDTMipsFlags));
default:
break;
}
@@ -2329,7 +2332,7 @@
return "REL";
if (Value == DT_RELA)
return "RELA";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DT_PLTGOT:
case DT_HASH:
case DT_STRTAB:
@@ -2387,9 +2390,9 @@
.str();
}
case DT_FLAGS:
- return FormatFlags(Value, makeArrayRef(ElfDynamicDTFlags));
+ return FormatFlags(Value, ArrayRef(ElfDynamicDTFlags));
case DT_FLAGS_1:
- return FormatFlags(Value, makeArrayRef(ElfDynamicDTFlags1));
+ return FormatFlags(Value, ArrayRef(ElfDynamicDTFlags1));
default:
return FormatHexValue(Value);
}
@@ -2551,7 +2554,7 @@
template <class ELFT>
static Expected<ArrayRef<typename ELFT::Word>>
-getGnuHashTableChains(Optional<DynRegionInfo> DynSymRegion,
+getGnuHashTableChains(std::optional<DynRegionInfo> DynSymRegion,
const typename ELFT::GnuHash *GnuHashTable) {
if (!DynSymRegion)
return createError("no dynamic symbol table found");
@@ -2796,9 +2799,9 @@
}
// Lookup dynamic table tags which define the GOT layout.
- Optional<uint64_t> DtPltGot;
- Optional<uint64_t> DtLocalGotNum;
- Optional<uint64_t> DtGotSym;
+ std::optional<uint64_t> DtPltGot;
+ std::optional<uint64_t> DtLocalGotNum;
+ std::optional<uint64_t> DtGotSym;
for (const auto &Entry : DynTable) {
switch (Entry.getTag()) {
case ELF::DT_PLTGOT:
@@ -2849,8 +2852,8 @@
template <class ELFT>
Error MipsGOTParser<ELFT>::findPLT(Elf_Dyn_Range DynTable) {
// Lookup dynamic table tags which define the PLT layout.
- Optional<uint64_t> DtMipsPltGot;
- Optional<uint64_t> DtJmpRel;
+ std::optional<uint64_t> DtMipsPltGot;
+ std::optional<uint64_t> DtJmpRel;
for (const auto &Entry : DynTable) {
switch (Entry.getTag()) {
case ELF::DT_MIPS_PLTGOT:
@@ -3294,7 +3297,7 @@
auto It = llvm::find_if(ElfObjectFileType, [&](const EnumEntry<unsigned> &E) {
return E.Value == Type;
});
- if (It != makeArrayRef(ElfObjectFileType).end())
+ if (It != ArrayRef(ElfObjectFileType).end())
return It;
return nullptr;
}
@@ -3317,9 +3320,9 @@
for (int i = 0; i < ELF::EI_NIDENT; i++)
OS << format(" %02x", static_cast<int>(e.e_ident[i]));
OS << "\n";
- Str = enumToString(e.e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass));
+ Str = enumToString(e.e_ident[ELF::EI_CLASS], ArrayRef(ElfClass));
printFields(OS, "Class:", Str);
- Str = enumToString(e.e_ident[ELF::EI_DATA], makeArrayRef(ElfDataEncoding));
+ Str = enumToString(e.e_ident[ELF::EI_DATA], ArrayRef(ElfDataEncoding));
printFields(OS, "Data:", Str);
OS.PadToColumn(2u);
OS << "Version:";
@@ -3328,7 +3331,7 @@
if (e.e_version == ELF::EV_CURRENT)
OS << " (current)";
OS << "\n";
- Str = enumToString(e.e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI));
+ Str = enumToString(e.e_ident[ELF::EI_OSABI], ArrayRef(ElfOSABI));
printFields(OS, "OS/ABI:", Str);
printFields(OS,
"ABI Version:", std::to_string(e.e_ident[ELF::EI_ABIVERSION]));
@@ -3345,7 +3348,7 @@
}
printFields(OS, "Type:", Str);
- Str = enumToString(e.e_machine, makeArrayRef(ElfMachineType));
+ Str = enumToString(e.e_machine, ArrayRef(ElfMachineType));
printFields(OS, "Machine:", Str);
Str = "0x" + utohexstr(e.e_version);
printFields(OS, "Version:", Str);
@@ -3357,18 +3360,21 @@
printFields(OS, "Start of section headers:", Str);
std::string ElfFlags;
if (e.e_machine == EM_MIPS)
- ElfFlags =
- printFlags(e.e_flags, makeArrayRef(ElfHeaderMipsFlags),
- unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI),
- unsigned(ELF::EF_MIPS_MACH));
+ ElfFlags = printFlags(
+ e.e_flags, ArrayRef(ElfHeaderMipsFlags), unsigned(ELF::EF_MIPS_ARCH),
+ unsigned(ELF::EF_MIPS_ABI), unsigned(ELF::EF_MIPS_MACH));
else if (e.e_machine == EM_RISCV)
- ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderRISCVFlags));
+ ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderRISCVFlags));
else if (e.e_machine == EM_AVR)
- ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderAVRFlags),
+ ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderAVRFlags),
unsigned(ELF::EF_AVR_ARCH_MASK));
else if (e.e_machine == EM_LOONGARCH)
- ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderLoongArchFlags),
- unsigned(ELF::EF_LOONGARCH_BASE_ABI_MASK));
+ ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderLoongArchFlags),
+ unsigned(ELF::EF_LOONGARCH_ABI_MODIFIER_MASK),
+ unsigned(ELF::EF_LOONGARCH_OBJABI_MASK));
+ else if (e.e_machine == EM_XTENSA)
+ ElfFlags = printFlags(e.e_flags, ArrayRef(ElfHeaderXtensaFlags),
+ unsigned(ELF::EF_XTENSA_MACH));
Str = "0x" + utohexstr(e.e_flags);
if (!ElfFlags.empty())
Str = Str + ", " + ElfFlags;
@@ -3537,7 +3543,7 @@
printField(F);
std::string Addend;
- if (Optional<int64_t> A = R.Addend) {
+ if (std::optional<int64_t> A = R.Addend) {
int64_t RelAddend = *A;
if (!RelSym.Name.empty()) {
if (RelAddend < 0) {
@@ -3693,8 +3699,16 @@
}
template <class ELFT> void GNUELFDumper<ELFT>::printSectionHeaders() {
- unsigned Bias = ELFT::Is64Bits ? 0 : 8;
ArrayRef<Elf_Shdr> Sections = cantFail(this->Obj.sections());
+ if (Sections.empty()) {
+ OS << "\nThere are no sections in this file.\n";
+ Expected<StringRef> SecStrTableOrErr =
+ this->Obj.getSectionStringTable(Sections, this->WarningHandler);
+ if (!SecStrTableOrErr)
+ this->reportUniqueWarning(SecStrTableOrErr.takeError());
+ return;
+ }
+ unsigned Bias = ELFT::Is64Bits ? 0 : 8;
OS << "There are " << to_string(Sections.size())
<< " section headers, starting at offset "
<< "0x" << utohexstr(this->Obj.getHeader().e_shoff, /*LowerCase=*/true) << ":\n\n";
@@ -3825,7 +3839,7 @@
template <class ELFT>
void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable,
+ std::optional<StringRef> StrTable,
bool IsDynamic,
bool NonVisibilityBitsUsed) const {
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
@@ -3839,14 +3853,14 @@
unsigned char SymbolType = Symbol.getType();
if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- Fields[3].Str = enumToString(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ Fields[3].Str = enumToString(SymbolType, ArrayRef(AMDGPUSymbolTypes));
else
- Fields[3].Str = enumToString(SymbolType, makeArrayRef(ElfSymbolTypes));
+ Fields[3].Str = enumToString(SymbolType, ArrayRef(ElfSymbolTypes));
Fields[4].Str =
- enumToString(Symbol.getBinding(), makeArrayRef(ElfSymbolBindings));
+ enumToString(Symbol.getBinding(), ArrayRef(ElfSymbolBindings));
Fields[5].Str =
- enumToString(Symbol.getVisibility(), makeArrayRef(ElfSymbolVisibilities));
+ enumToString(Symbol.getVisibility(), ArrayRef(ElfSymbolVisibilities));
if (Symbol.st_other & ~0x3) {
if (this->Obj.getHeader().e_machine == ELF::EM_AARCH64) {
@@ -3902,14 +3916,14 @@
unsigned char SymbolType = Symbol->getType();
if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- Fields[4].Str = enumToString(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ Fields[4].Str = enumToString(SymbolType, ArrayRef(AMDGPUSymbolTypes));
else
- Fields[4].Str = enumToString(SymbolType, makeArrayRef(ElfSymbolTypes));
+ Fields[4].Str = enumToString(SymbolType, ArrayRef(ElfSymbolTypes));
Fields[5].Str =
- enumToString(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
- Fields[6].Str = enumToString(Symbol->getVisibility(),
- makeArrayRef(ElfSymbolVisibilities));
+ enumToString(Symbol->getBinding(), ArrayRef(ElfSymbolBindings));
+ Fields[6].Str =
+ enumToString(Symbol->getVisibility(), ArrayRef(ElfSymbolVisibilities));
Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex, ShndxTable);
Fields[8].Str =
this->getFullSymbolName(*Symbol, SymIndex, ShndxTable, StrTable, true);
@@ -4074,6 +4088,14 @@
template <class ELFT> void GNUELFDumper<ELFT>::printSectionDetails() {
ArrayRef<Elf_Shdr> Sections = cantFail(this->Obj.sections());
+ if (Sections.empty()) {
+ OS << "\nThere are no sections in this file.\n";
+ Expected<StringRef> SecStrTableOrErr =
+ this->Obj.getSectionStringTable(Sections, this->WarningHandler);
+ if (!SecStrTableOrErr)
+ this->reportUniqueWarning(SecStrTableOrErr.takeError());
+ return;
+ }
OS << "There are " << to_string(Sections.size())
<< " section headers, starting at offset "
<< "0x" << utohexstr(this->Obj.getHeader().e_shoff, /*LowerCase=*/true) << ":\n\n";
@@ -4171,6 +4193,30 @@
OS << "\n";
++SectionIndex;
+
+ if (!(S.sh_flags & SHF_COMPRESSED))
+ continue;
+ Expected<ArrayRef<uint8_t>> Data = this->Obj.getSectionContents(S);
+ if (!Data || Data->size() < sizeof(Elf_Chdr)) {
+ consumeError(Data.takeError());
+ reportWarning(createError("SHF_COMPRESSED section '" + Name +
+ "' does not have an Elf_Chdr header"),
+ this->FileName);
+ OS.indent(7);
+ OS << "[<corrupt>]";
+ } else {
+ OS.indent(7);
+ auto *Chdr = reinterpret_cast<const Elf_Chdr *>(Data->data());
+ if (Chdr->ch_type == ELFCOMPRESS_ZLIB)
+ OS << "ZLIB";
+ else if (Chdr->ch_type == ELFCOMPRESS_ZSTD)
+ OS << "ZSTD";
+ else
+ OS << format("[<unknown>: 0x%x]", unsigned(Chdr->ch_type));
+ OS << ", " << format_hex_no_prefix(Chdr->ch_size, ELFT::Is64Bits ? 16 : 8)
+ << ", " << Chdr->ch_addralign;
+ }
+ OS << '\n';
}
}
@@ -4257,12 +4303,21 @@
template <class ELFT>
void GNUELFDumper<ELFT>::printProgramHeaders(
bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) {
- if (PrintProgramHeaders)
- printProgramHeaders();
+ const bool ShouldPrintSectionMapping = (PrintSectionMapping != cl::BOU_FALSE);
+ // Exit early if no program header or section mapping details were requested.
+ if (!PrintProgramHeaders && !ShouldPrintSectionMapping)
+ return;
- // Display the section mapping along with the program headers, unless
- // -section-mapping is explicitly set to false.
- if (PrintSectionMapping != cl::BOU_FALSE)
+ if (PrintProgramHeaders) {
+ const Elf_Ehdr &Header = this->Obj.getHeader();
+ if (Header.e_phnum == 0) {
+ OS << "\nThere are no program headers in this file.\n";
+ } else {
+ printProgramHeaders();
+ }
+ }
+
+ if (ShouldPrintSectionMapping)
printSectionMapping();
}
@@ -4272,7 +4327,7 @@
Field Fields[8] = {2, 17, 26, 37 + Bias,
48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias};
OS << "\nElf file type is "
- << enumToString(Header.e_type, makeArrayRef(ElfObjectFileType)) << "\n"
+ << enumToString(Header.e_type, ArrayRef(ElfObjectFileType)) << "\n"
<< "Entry point " << format_hex(Header.e_entry, 3) << "\n"
<< "There are " << Header.e_phnum << " program headers,"
<< " starting at offset " << Header.e_phoff << "\n\n"
@@ -4565,8 +4620,8 @@
return;
}
- SmallVector<Optional<VersionEntry>, 0> *VersionMap = nullptr;
- if (Expected<SmallVector<Optional<VersionEntry>, 0> *> MapOrErr =
+ SmallVector<std::optional<VersionEntry>, 0> *VersionMap = nullptr;
+ if (Expected<SmallVector<std::optional<VersionEntry>, 0> *> MapOrErr =
this->getVersionMap())
VersionMap = *MapOrErr;
else
@@ -4588,7 +4643,7 @@
bool IsDefault;
Expected<StringRef> NameOrErr = this->Obj.getSymbolVersionByIndex(
- Ndx, IsDefault, *VersionMap, /*IsSymHidden=*/None);
+ Ndx, IsDefault, *VersionMap, /*IsSymHidden=*/std::nullopt);
if (!NameOrErr) {
this->reportUniqueWarning("unable to get a version for entry " +
Twine(I) + " of " + this->describe(*Sec) +
@@ -5039,7 +5094,7 @@
"Linux", "Hurd", "Solaris", "FreeBSD", "NetBSD", "Syllable", "NaCl",
};
StringRef OSName = "Unknown";
- if (Words[0] < array_lengthof(OSNames))
+ if (Words[0] < std::size(OSNames))
OSName = OSNames[Words[0]];
uint32_t Major = Words[1], Minor = Words[2], Patch = Words[3];
std::string str;
@@ -5178,14 +5233,14 @@
};
template <typename ELFT>
-static Optional<FreeBSDNote>
+static std::optional<FreeBSDNote>
getFreeBSDNote(uint32_t NoteType, ArrayRef<uint8_t> Desc, bool IsCore) {
if (IsCore)
- return None; // No pretty-printing yet.
+ return std::nullopt; // No pretty-printing yet.
switch (NoteType) {
case ELF::NT_FREEBSD_ABI_TAG:
if (Desc.size() != 4)
- return None;
+ return std::nullopt;
return FreeBSDNote{
"ABI tag",
utostr(support::endian::read32<ELFT::TargetEndianness>(Desc.data()))};
@@ -5193,12 +5248,12 @@
return FreeBSDNote{"Arch tag", toStringRef(Desc).str()};
case ELF::NT_FREEBSD_FEATURE_CTL: {
if (Desc.size() != 4)
- return None;
+ return std::nullopt;
unsigned Value =
support::endian::read32<ELFT::TargetEndianness>(Desc.data());
std::string FlagsStr;
raw_string_ostream OS(FlagsStr);
- printFlags(Value, makeArrayRef(FreeBSDFeatureCtlFlags), OS);
+ printFlags(Value, ArrayRef(FreeBSDFeatureCtlFlags), OS);
if (OS.str().empty())
OS << "0x" << utohexstr(Value);
else
@@ -5206,7 +5261,7 @@
return FreeBSDNote{"Feature flags", OS.str()};
}
default:
- return None;
+ return std::nullopt;
}
}
@@ -5628,7 +5683,7 @@
template <class ELFT>
static void printNotesHelper(
const ELFDumper<ELFT> &Dumper,
- llvm::function_ref<void(Optional<StringRef>, typename ELFT::Off,
+ llvm::function_ref<void(std::optional<StringRef>, typename ELFT::Off,
typename ELFT::Addr)>
StartNotesFn,
llvm::function_ref<Error(const typename ELFT::Note &, bool)> ProcessNoteFn,
@@ -5641,7 +5696,7 @@
for (const typename ELFT::Shdr &S : Sections) {
if (S.sh_type != SHT_NOTE)
continue;
- StartNotesFn(expectedToOptional(Obj.getSectionName(S)), S.sh_offset,
+ StartNotesFn(expectedToStdOptional(Obj.getSectionName(S)), S.sh_offset,
S.sh_size);
Error Err = Error::success();
size_t I = 0;
@@ -5673,7 +5728,7 @@
const typename ELFT::Phdr &P = (*PhdrsOrErr)[I];
if (P.p_type != PT_NOTE)
continue;
- StartNotesFn(/*SecName=*/None, P.p_offset, P.p_filesz);
+ StartNotesFn(/*SecName=*/std::nullopt, P.p_offset, P.p_filesz);
Error Err = Error::success();
size_t Index = 0;
for (const typename ELFT::Note Note : Obj.notes(P, Err)) {
@@ -5694,7 +5749,7 @@
template <class ELFT> void GNUELFDumper<ELFT>::printNotes() {
bool IsFirstHeader = true;
- auto PrintHeader = [&](Optional<StringRef> SecName,
+ auto PrintHeader = [&](std::optional<StringRef> SecName,
const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
// Print a newline between notes sections to match GNU readelf.
@@ -5737,7 +5792,7 @@
if (printGNUNote<ELFT>(OS, Type, Descriptor))
return Error::success();
} else if (Name == "FreeBSD") {
- if (Optional<FreeBSDNote> N =
+ if (std::optional<FreeBSDNote> N =
getFreeBSDNote<ELFT>(Type, Descriptor, IsCore)) {
OS << " " << N->Type << ": " << N->Value << '\n';
return Error::success();
@@ -5950,7 +6005,7 @@
template <class ELFT>
SmallVector<uint32_t> ELFDumper<ELFT>::getSymbolIndexesForFunctionAddress(
- uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec) {
+ uint64_t SymValue, std::optional<const Elf_Shdr *> FunctionSec) {
SmallVector<uint32_t> SymbolIndexes;
if (!this->AddressToIndexMap) {
// Populate the address to index map upon the first invocation of this
@@ -6016,7 +6071,7 @@
template <class ELFT>
bool ELFDumper<ELFT>::printFunctionStackSize(
- uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec,
+ uint64_t SymValue, std::optional<const Elf_Shdr *> FunctionSec,
const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) {
SmallVector<uint32_t> FuncSymIndexes =
this->getSymbolIndexesForFunctionAddress(SymValue, FunctionSec);
@@ -6134,8 +6189,8 @@
break;
}
uint64_t SymValue = Data.getAddress(&Offset);
- if (!printFunctionStackSize(SymValue, /*FunctionSec=*/None, Sec, Data,
- &Offset))
+ if (!printFunctionStackSize(SymValue, /*FunctionSec=*/std::nullopt, Sec,
+ Data, &Offset))
break;
}
}
@@ -6322,7 +6377,7 @@
OS.PadToColumn(31 + 2 * Bias);
OS << to_string(format_hex_no_prefix(Sym.st_value, 8 + Bias));
OS.PadToColumn(40 + 3 * Bias);
- OS << enumToString(Sym.getType(), makeArrayRef(ElfSymbolTypes));
+ OS << enumToString(Sym.getType(), ArrayRef(ElfSymbolTypes));
OS.PadToColumn(48 + 3 * Bias);
OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(),
ShndxTable);
@@ -6376,7 +6431,7 @@
OS.PadToColumn(20 + 2 * Bias);
OS << to_string(format_hex_no_prefix(Sym.st_value, 8 + Bias));
OS.PadToColumn(29 + 3 * Bias);
- OS << enumToString(Sym.getType(), makeArrayRef(ElfSymbolTypes));
+ OS << enumToString(Sym.getType(), ArrayRef(ElfSymbolTypes));
OS.PadToColumn(37 + 3 * Bias);
OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(),
ShndxTable);
@@ -6423,15 +6478,15 @@
OS << "GPR size: " << getMipsRegisterSize(Flags->gpr_size) << "\n";
OS << "CPR1 size: " << getMipsRegisterSize(Flags->cpr1_size) << "\n";
OS << "CPR2 size: " << getMipsRegisterSize(Flags->cpr2_size) << "\n";
- OS << "FP ABI: "
- << enumToString(Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)) << "\n";
+ OS << "FP ABI: " << enumToString(Flags->fp_abi, ArrayRef(ElfMipsFpABIType))
+ << "\n";
OS << "ISA Extension: "
- << enumToString(Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)) << "\n";
+ << enumToString(Flags->isa_ext, ArrayRef(ElfMipsISAExtType)) << "\n";
if (Flags->ases == 0)
OS << "ASEs: None\n";
else
// FIXME: Print each flag on a separate line.
- OS << "ASEs: " << printFlags(Flags->ases, makeArrayRef(ElfMipsASEFlags))
+ OS << "ASEs: " << printFlags(Flags->ases, ArrayRef(ElfMipsASEFlags))
<< "\n";
OS << "FLAGS 1: " << format_hex_no_prefix(Flags->flags1, 8, false) << "\n";
OS << "FLAGS 2: " << format_hex_no_prefix(Flags->flags2, 8, false) << "\n";
@@ -6444,30 +6499,32 @@
DictScope D(W, "ElfHeader");
{
DictScope D(W, "Ident");
- W.printBinary("Magic", makeArrayRef(E.e_ident).slice(ELF::EI_MAG0, 4));
- W.printEnum("Class", E.e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass));
+ W.printBinary("Magic",
+ ArrayRef<unsigned char>(E.e_ident).slice(ELF::EI_MAG0, 4));
+ W.printEnum("Class", E.e_ident[ELF::EI_CLASS], ArrayRef(ElfClass));
W.printEnum("DataEncoding", E.e_ident[ELF::EI_DATA],
- makeArrayRef(ElfDataEncoding));
+ ArrayRef(ElfDataEncoding));
W.printNumber("FileVersion", E.e_ident[ELF::EI_VERSION]);
- auto OSABI = makeArrayRef(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 = makeArrayRef(AMDGPUElfOSABI);
+ OSABI = ArrayRef(AMDGPUElfOSABI);
break;
case ELF::EM_ARM:
- OSABI = makeArrayRef(ARMElfOSABI);
+ OSABI = ArrayRef(ARMElfOSABI);
break;
case ELF::EM_TI_C6000:
- OSABI = makeArrayRef(C6000ElfOSABI);
+ OSABI = ArrayRef(C6000ElfOSABI);
break;
}
}
W.printEnum("OS/ABI", E.e_ident[ELF::EI_OSABI], OSABI);
W.printNumber("ABIVersion", E.e_ident[ELF::EI_ABIVERSION]);
- W.printBinary("Unused", makeArrayRef(E.e_ident).slice(ELF::EI_PAD));
+ W.printBinary("Unused",
+ ArrayRef<unsigned char>(E.e_ident).slice(ELF::EI_PAD));
}
std::string TypeStr;
@@ -6483,13 +6540,13 @@
}
W.printString("Type", TypeStr + " (0x" + utohexstr(E.e_type) + ")");
- W.printEnum("Machine", E.e_machine, makeArrayRef(ElfMachineType));
+ W.printEnum("Machine", E.e_machine, ArrayRef(ElfMachineType));
W.printNumber("Version", E.e_version);
W.printHex("Entry", E.e_entry);
W.printHex("ProgramHeaderOffset", E.e_phoff);
W.printHex("SectionHeaderOffset", E.e_shoff);
if (E.e_machine == EM_MIPS)
- W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderMipsFlags),
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderMipsFlags),
unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI),
unsigned(ELF::EF_MIPS_MACH));
else if (E.e_machine == EM_AMDGPU) {
@@ -6499,29 +6556,33 @@
break;
case 0:
// ELFOSABI_AMDGPU_PAL, ELFOSABI_AMDGPU_MESA3D support *_V3 flags.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ELF::ELFABIVERSION_AMDGPU_HSA_V3:
W.printFlags("Flags", E.e_flags,
- makeArrayRef(ElfHeaderAMDGPUFlagsABIVersion3),
+ ArrayRef(ElfHeaderAMDGPUFlagsABIVersion3),
unsigned(ELF::EF_AMDGPU_MACH));
break;
case ELF::ELFABIVERSION_AMDGPU_HSA_V4:
case ELF::ELFABIVERSION_AMDGPU_HSA_V5:
W.printFlags("Flags", E.e_flags,
- makeArrayRef(ElfHeaderAMDGPUFlagsABIVersion4),
+ ArrayRef(ElfHeaderAMDGPUFlagsABIVersion4),
unsigned(ELF::EF_AMDGPU_MACH),
unsigned(ELF::EF_AMDGPU_FEATURE_XNACK_V4),
unsigned(ELF::EF_AMDGPU_FEATURE_SRAMECC_V4));
break;
}
} else if (E.e_machine == EM_RISCV)
- W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderRISCVFlags));
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderRISCVFlags));
else if (E.e_machine == EM_AVR)
- W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderAVRFlags),
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderAVRFlags),
unsigned(ELF::EF_AVR_ARCH_MASK));
else if (E.e_machine == EM_LOONGARCH)
- W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderLoongArchFlags),
- unsigned(ELF::EF_LOONGARCH_BASE_ABI_MASK));
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderLoongArchFlags),
+ unsigned(ELF::EF_LOONGARCH_ABI_MODIFIER_MASK),
+ unsigned(ELF::EF_LOONGARCH_OBJABI_MASK));
+ else if (E.e_machine == EM_XTENSA)
+ W.printFlags("Flags", E.e_flags, ArrayRef(ElfHeaderXtensaFlags),
+ unsigned(ELF::EF_XTENSA_MACH));
else
W.printFlags("Flags", E.e_flags);
W.printNumber("HeaderSize", E.e_ehsize);
@@ -6627,7 +6688,7 @@
object::getELFSectionTypeName(this->Obj.getHeader().e_machine,
Sec.sh_type),
Sec.sh_type);
- W.printFlags("Flags", Sec.sh_flags, makeArrayRef(FlagsList));
+ W.printFlags("Flags", Sec.sh_flags, ArrayRef(FlagsList));
W.printHex("Address", Sec.sh_addr);
W.printHex("Offset", Sec.sh_offset);
W.printNumber("Size", Sec.sh_size);
@@ -6676,7 +6737,7 @@
void LLVMELFDumper<ELFT>::printSymbolSection(
const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const {
- auto GetSectionSpecialType = [&]() -> Optional<StringRef> {
+ auto GetSectionSpecialType = [&]() -> std::optional<StringRef> {
if (Symbol.isUndefined())
return StringRef("Undefined");
if (Symbol.isProcessorSpecific())
@@ -6689,10 +6750,10 @@
return StringRef("Common");
if (Symbol.isReserved() && Symbol.st_shndx != SHN_XINDEX)
return StringRef("Reserved");
- return None;
+ return std::nullopt;
};
- if (Optional<StringRef> Type = GetSectionSpecialType()) {
+ if (std::optional<StringRef> Type = GetSectionSpecialType()) {
W.printHex("Section", *Type, Symbol.st_shndx);
return;
}
@@ -6726,7 +6787,7 @@
template <class ELFT>
void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
- Optional<StringRef> StrTable,
+ std::optional<StringRef> StrTable,
bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) const {
std::string FullSymbolName = this->getFullSymbolName(
@@ -6737,12 +6798,12 @@
W.printNumber("Name", FullSymbolName, Symbol.st_name);
W.printHex("Value", Symbol.st_value);
W.printNumber("Size", Symbol.st_size);
- W.printEnum("Binding", Symbol.getBinding(), makeArrayRef(ElfSymbolBindings));
+ W.printEnum("Binding", Symbol.getBinding(), ArrayRef(ElfSymbolBindings));
if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- W.printEnum("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ W.printEnum("Type", SymbolType, ArrayRef(AMDGPUSymbolTypes));
else
- W.printEnum("Type", SymbolType, makeArrayRef(ElfSymbolTypes));
+ W.printEnum("Type", SymbolType, ArrayRef(ElfSymbolTypes));
if (Symbol.st_other == 0)
// Usually st_other flag is zero. Do not pollute the output
// by flags enumeration in that case.
@@ -6771,7 +6832,7 @@
std::begin(ElfRISCVSymOtherFlags),
std::end(ElfRISCVSymOtherFlags));
}
- W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u);
+ W.printFlags("Other", Symbol.st_other, ArrayRef(SymOtherFlags), 0x3u);
}
printSymbolSection(Symbol, SymIndex, ShndxTable);
}
@@ -6854,7 +6915,7 @@
W.printHex("PhysicalAddress", Phdr.p_paddr);
W.printNumber("FileSize", Phdr.p_filesz);
W.printNumber("MemSize", Phdr.p_memsz);
- W.printFlags("Flags", Phdr.p_flags, makeArrayRef(ElfSegmentFlags));
+ W.printFlags("Flags", Phdr.p_flags, ArrayRef(ElfSegmentFlags));
W.printNumber("Alignment", Phdr.p_align);
}
}
@@ -6908,7 +6969,7 @@
for (const VerDef &D : *V) {
DictScope Def(W, "Definition");
W.printNumber("Version", D.Version);
- W.printFlags("Flags", D.Flags, makeArrayRef(SymVersionFlags));
+ W.printFlags("Flags", D.Flags, ArrayRef(SymVersionFlags));
W.printNumber("Index", D.Ndx);
W.printNumber("Hash", D.Hash);
W.printString("Name", D.Name.c_str());
@@ -6941,7 +7002,7 @@
for (const VernAux &Aux : VN.AuxV) {
DictScope Entry(W, "Entry");
W.printNumber("Hash", Aux.Hash);
- W.printFlags("Flags", Aux.Flags, makeArrayRef(SymVersionFlags));
+ W.printFlags("Flags", Aux.Flags, ArrayRef(SymVersionFlags));
W.printNumber("Index", Aux.Other);
W.printString("Name", Aux.Name.c_str());
}
@@ -7053,7 +7114,7 @@
Sec.sh_type != SHT_LLVM_BB_ADDR_MAP_V0) {
continue;
}
- Optional<const Elf_Shdr *> FunctionSec = None;
+ std::optional<const Elf_Shdr *> FunctionSec;
if (IsRelocatable)
FunctionSec =
unwrapOrError(this->FileName, this->Obj.getSection(Sec.sh_link));
@@ -7082,6 +7143,7 @@
ListScope L(W, "BB entries");
for (const BBAddrMap::BBEntry &BBE : AM.BBEntries) {
DictScope L(W);
+ W.printNumber("ID", BBE.ID);
W.printHex("Offset", BBE.Offset);
W.printHex("Size", BBE.Size);
W.printBoolean("HasReturn", BBE.HasReturn);
@@ -7189,7 +7251,7 @@
ListScope L(W, "Notes");
std::unique_ptr<DictScope> NoteScope;
- auto StartNotes = [&](Optional<StringRef> SecName,
+ auto StartNotes = [&](std::optional<StringRef> SecName,
const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
NoteScope = std::make_unique<DictScope>(W, "NoteSection");
@@ -7224,7 +7286,7 @@
if (printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W))
return Error::success();
} else if (Name == "FreeBSD") {
- if (Optional<FreeBSDNote> N =
+ if (std::optional<FreeBSDNote> N =
getFreeBSDNote<ELFT>(Type, Descriptor, IsCore)) {
W.printString(N->Type, N->Value);
return Error::success();
@@ -7381,7 +7443,7 @@
const Elf_Sym &Sym = *Parser.getGotSym(&E);
W.printHex("Value", Sym.st_value);
- W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes));
+ W.printEnum("Type", Sym.getType(), ArrayRef(ElfSymbolTypes));
const unsigned SymIndex = &Sym - this->dynamic_symbols().begin();
DataRegion<Elf_Word> ShndxTable(
@@ -7431,7 +7493,7 @@
const Elf_Sym &Sym = *Parser.getPltSym(&E);
W.printHex("Value", Sym.st_value);
- W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes));
+ W.printEnum("Type", Sym.getType(), ArrayRef(ElfSymbolTypes));
printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin(),
ShndxTable);
@@ -7468,13 +7530,13 @@
else
OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev);
OS << "\n";
- W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType));
- W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags));
- W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType));
+ W.printEnum("ISA Extension", Flags->isa_ext, ArrayRef(ElfMipsISAExtType));
+ W.printFlags("ASEs", Flags->ases, ArrayRef(ElfMipsASEFlags));
+ W.printEnum("FP ABI", Flags->fp_abi, ArrayRef(ElfMipsFpABIType));
W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size));
W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size));
W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size));
- W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1));
+ W.printFlags("Flags 1", Flags->flags1, ArrayRef(ElfMipsFlags1));
W.printHex("Flags 2", Flags->flags2);
}
@@ -7482,7 +7544,7 @@
void JSONELFDumper<ELFT>::printFileSummary(StringRef FileStr, ObjectFile &Obj,
ArrayRef<std::string> InputFilenames,
const Archive *A) {
- FileScope = std::make_unique<DictScope>(this->W, FileStr);
+ FileScope = std::make_unique<DictScope>(this->W);
DictScope D(this->W, "FileSummary");
this->W.printString("File", FileStr);
this->W.printString("Format", Obj.getFileFormatName());
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp
index 4931ab5..5b38501 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -13,7 +13,6 @@
#include "ObjDumper.h"
#include "StackMapPrinter.h"
#include "llvm-readobj.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Object/MachO.h"
@@ -61,9 +60,9 @@
uint8_t getSymbolType(const SymbolRef &Symbol) const;
void printSymbols() override;
- void printSymbols(Optional<SymbolComparator> SymComp) override;
+ void printSymbols(std::optional<SymbolComparator> SymComp) override;
void printDynamicSymbols() override;
- void printDynamicSymbols(Optional<SymbolComparator> SymComp) override;
+ void printDynamicSymbols(std::optional<SymbolComparator> SymComp) override;
void printSymbol(const SymbolRef &Symbol, ScopedPrinter &W);
void printSymbol(const SymbolRef &Symbol);
@@ -432,36 +431,36 @@
template<class MachHeader>
void MachODumper::printFileHeaders(const MachHeader &Header) {
- W.printEnum("Magic", Header.magic, makeArrayRef(MachOMagics));
- W.printEnum("CpuType", Header.cputype, makeArrayRef(MachOHeaderCpuTypes));
+ W.printEnum("Magic", Header.magic, ArrayRef(MachOMagics));
+ W.printEnum("CpuType", Header.cputype, ArrayRef(MachOHeaderCpuTypes));
uint32_t subtype = Header.cpusubtype & ~MachO::CPU_SUBTYPE_MASK;
switch (Header.cputype) {
case MachO::CPU_TYPE_X86:
- W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX86));
+ W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesX86));
break;
case MachO::CPU_TYPE_X86_64:
- W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX64));
+ W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesX64));
break;
case MachO::CPU_TYPE_ARM:
- W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM));
+ W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesARM));
break;
case MachO::CPU_TYPE_POWERPC:
- W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesPPC));
+ W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesPPC));
break;
case MachO::CPU_TYPE_SPARC:
- W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesSPARC));
+ W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesSPARC));
break;
case MachO::CPU_TYPE_ARM64:
- W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM64));
+ W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesARM64));
break;
case MachO::CPU_TYPE_POWERPC64:
default:
W.printHex("CpuSubtype", subtype);
}
- W.printEnum("FileType", Header.filetype, makeArrayRef(MachOHeaderFileTypes));
+ W.printEnum("FileType", Header.filetype, ArrayRef(MachOHeaderFileTypes));
W.printNumber("NumOfLoadCommands", Header.ncmds);
W.printNumber("SizeOfLoadCommands", Header.sizeofcmds);
- W.printFlags("Flags", Header.flags, makeArrayRef(MachOHeaderFlags));
+ W.printFlags("Flags", Header.flags, ArrayRef(MachOHeaderFlags));
}
void MachODumper::printSectionHeaders() { return printSectionHeaders(Obj); }
@@ -491,10 +490,9 @@
W.printNumber("Alignment", MOSection.Alignment);
W.printHex("RelocationOffset", MOSection.RelocationTableOffset);
W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries);
- W.printEnum("Type", MOSection.Flags & 0xFF,
- makeArrayRef(MachOSectionTypes));
+ W.printEnum("Type", MOSection.Flags & 0xFF, ArrayRef(MachOSectionTypes));
W.printFlags("Attributes", MOSection.Flags >> 8,
- makeArrayRef(MachOSectionAttributes));
+ ArrayRef(MachOSectionAttributes));
W.printHex("Reserved1", MOSection.Reserved1);
W.printHex("Reserved2", MOSection.Reserved2);
if (Obj->is64Bit())
@@ -634,9 +632,9 @@
return getSymbolType(LHS) < getSymbolType(RHS);
}
-void MachODumper::printSymbols() { printSymbols(None); }
+void MachODumper::printSymbols() { printSymbols(std::nullopt); }
-void MachODumper::printSymbols(Optional<SymbolComparator> SymComp) {
+void MachODumper::printSymbols(std::optional<SymbolComparator> SymComp) {
ListScope Group(W, "Symbols");
if (SymComp) {
auto SymbolRange = Obj->symbols();
@@ -655,7 +653,7 @@
void MachODumper::printDynamicSymbols() {
ListScope Group(W, "DynamicSymbols");
}
-void MachODumper::printDynamicSymbols(Optional<SymbolComparator> SymComp) {
+void MachODumper::printDynamicSymbols(std::optional<SymbolComparator> SymComp) {
ListScope Group(W, "DynamicSymbols");
}
@@ -695,13 +693,13 @@
if (MOSymbol.Type & MachO::N_EXT)
W.startLine() << "Extern\n";
W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE),
- makeArrayRef(MachOSymbolTypes));
+ ArrayRef(MachOSymbolTypes));
}
W.printHex("Section", SectionName, MOSymbol.SectionIndex);
W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0x7),
- makeArrayRef(MachOSymbolRefTypes));
+ ArrayRef(MachOSymbolRefTypes));
W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0x7),
- makeArrayRef(MachOSymbolFlags));
+ ArrayRef(MachOSymbolFlags));
W.printHex("Value", MOSymbol.Value);
}
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h b/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h
index 292efd2..258d872 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h
@@ -13,7 +13,6 @@
#include <memory>
#include <system_error>
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -85,7 +84,7 @@
printDynamicSymbols();
}
virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
- llvm::Optional<SymbolComparator> SymComp) {
+ std::optional<SymbolComparator> SymComp) {
if (SymComp) {
if (PrintSymbols)
printSymbols(SymComp);
@@ -155,8 +154,12 @@
llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes,
bool GHash) {}
- // Only implement for XCOFF
+ // Only implemented for XCOFF.
+ virtual void printStringTable() {}
virtual void printAuxiliaryHeader() {}
+ virtual void printExceptionSection() {}
+ virtual void printLoaderSection(bool PrintHeader, bool PrintSymbols,
+ bool PrintRelocations) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }
@@ -166,9 +169,6 @@
virtual void printMachOIndirectSymbols() { }
virtual void printMachOLinkerOptions() { }
- // Currently only implemented for XCOFF.
- virtual void printStringTable() { }
-
virtual void printStackMap() const = 0;
void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0);
@@ -187,9 +187,9 @@
private:
virtual void printSymbols() {}
- virtual void printSymbols(llvm::Optional<SymbolComparator> Comp) {}
+ virtual void printSymbols(std::optional<SymbolComparator> Comp) {}
virtual void printDynamicSymbols() {}
- virtual void printDynamicSymbols(llvm::Optional<SymbolComparator> Comp) {}
+ virtual void printDynamicSymbols(std::optional<SymbolComparator> Comp) {}
virtual void printProgramHeaders() {}
virtual void printSectionMapping() {}
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/Opts.td b/src/llvm-project/llvm/tools/llvm-readobj/Opts.td
index 4687fc7..4f7b12f 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/Opts.td
+++ b/src/llvm-project/llvm/tools/llvm-readobj/Opts.td
@@ -88,6 +88,10 @@
// XCOFF specific options.
def grp_xcoff : OptionGroup<"kind">, HelpText<"OPTIONS (XCOFF specific)">;
def auxiliary_header : FF<"auxiliary-header" , "Display the auxiliary header">, Group<grp_xcoff>;
+def exception_section : FF<"exception-section" , "Display the exception section entries">, Group<grp_xcoff>;
+def loader_section_header : FF<"loader-section-header" , "Display the loader section header">, Group<grp_xcoff>;
+def loader_section_symbols : FF<"loader-section-symbols" , "Display the loader section symbol table">, Group<grp_xcoff>;
+def loader_section_relocations : FF<"loader-section-relocations" , "Display the loader section relocation entries">, Group<grp_xcoff>;
def help : FF<"help", "Display this help">;
def version : FF<"version", "Display the version">;
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp
index cf80a2d..e6f0ac7 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -156,7 +156,7 @@
for (const SectionRef &Section : Obj->sections()) {
const WasmSection &WasmSec = Obj->getWasmSection(Section);
DictScope SectionD(W, "Section");
- W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes));
+ W.printEnum("Type", WasmSec.Type, ArrayRef(WasmSectionTypes));
W.printNumber("Size", static_cast<uint64_t>(WasmSec.Content.size()));
W.printNumber("Offset", WasmSec.Offset);
switch (WasmSec.Type) {
@@ -221,8 +221,8 @@
DictScope D(W, "Symbol");
WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl());
W.printString("Name", Symbol.Info.Name);
- W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes));
- W.printFlags("Flags", Symbol.Info.Flags, makeArrayRef(WasmSymbolFlags));
+ W.printEnum("Type", Symbol.Info.Kind, ArrayRef(WasmSymbolTypes));
+ W.printFlags("Flags", Symbol.Info.Flags, ArrayRef(WasmSymbolFlags));
if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) {
if (Symbol.Info.ImportName) {
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
index da964d3..2896f20 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -315,11 +315,11 @@
off_t Offset, const UnwindInfo &UI) {
DictScope UIS(SW, "UnwindInfo");
SW.printNumber("Version", UI.getVersion());
- SW.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags));
+ SW.printFlags("Flags", UI.getFlags(), ArrayRef(UnwindFlags));
SW.printNumber("PrologSize", UI.PrologSize);
if (UI.getFrameRegister()) {
SW.printEnum("FrameRegister", UI.getFrameRegister(),
- makeArrayRef(UnwindOpInfo));
+ ArrayRef(UnwindOpInfo));
SW.printHex("FrameOffset", UI.getFrameOffset());
} else {
SW.printString("FrameRegister", StringRef("-"));
@@ -337,7 +337,7 @@
return;
}
- printUnwindCode(UI, makeArrayRef(UCI, UCE));
+ printUnwindCode(UI, ArrayRef(UCI, UCE));
UCI = UCI + UsedSlots - 1;
}
}
diff --git a/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp
index ccae66f..56f672b 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -39,6 +39,9 @@
void printStackMap() const override;
void printNeededLibraries() override;
void printStringTable() override;
+ void printExceptionSection() override;
+ void printLoaderSection(bool PrintHeader, bool PrintSymbols,
+ bool PrintRelocations) override;
ScopedPrinter &getScopedPrinter() const { return W; }
@@ -46,6 +49,9 @@
template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
template <typename T> void printGenericSectionHeader(T &Sec) const;
template <typename T> void printOverflowSectionHeader(T &Sec) const;
+ template <typename T>
+ void printExceptionSectionEntry(const T &ExceptionSectEnt) const;
+ template <typename T> void printExceptionSectionEntries() const;
template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress);
void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
@@ -62,7 +68,20 @@
void printRelocations(ArrayRef<Shdr> Sections);
void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
+ void printLoaderSectionHeader(uintptr_t LoaderSectAddr);
+ void printLoaderSectionSymbols(uintptr_t LoaderSectAddr);
+ template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
+ void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr);
+ template <typename LoadSectionRelocTy>
+ void printLoaderSectionRelocationEntry(LoadSectionRelocTy *LoaderSecRelEntPtr,
+ StringRef SymbolName);
+ void printLoaderSectionRelocationEntries(uintptr_t LoaderSectAddr);
+ template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
+ typename LoaderSectionRelocationEntry>
+ void printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectAddr);
+
const XCOFFObjectFile &Obj;
+ const static int32_t FirstSymIdxOfLoaderSec = 3;
};
} // anonymous namespace
@@ -129,11 +148,127 @@
printSectionHeaders(Obj.sections32());
}
-void XCOFFDumper::printRelocations() {
+void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbols,
+ bool PrintRelocations) {
+ DictScope DS(W, "Loader Section");
+ Expected<uintptr_t> LoaderSectionAddrOrError =
+ Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
+ if (!LoaderSectionAddrOrError) {
+ reportUniqueWarning(LoaderSectionAddrOrError.takeError());
+ return;
+ }
+ uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
+
+ if (LoaderSectionAddr == 0)
+ return;
+
+ W.indent();
+ if (PrintHeader)
+ printLoaderSectionHeader(LoaderSectionAddr);
+
+ if (PrintSymbols)
+ printLoaderSectionSymbols(LoaderSectionAddr);
+
+ if (PrintRelocations)
+ printLoaderSectionRelocationEntries(LoaderSectionAddr);
+
+ W.unindent();
+}
+
+void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) {
+ DictScope DS(W, "Loader Section Header");
+
+ auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) {
+ W.printNumber("Version", LDHeader->Version);
+ W.printNumber("NumberOfSymbolEntries", LDHeader->NumberOfSymTabEnt);
+ W.printNumber("NumberOfRelocationEntries", LDHeader->NumberOfRelTabEnt);
+ W.printNumber("LengthOfImportFileIDStringTable",
+ LDHeader->LengthOfImpidStrTbl);
+ W.printNumber("NumberOfImportFileIDs", LDHeader->NumberOfImpid);
+ W.printHex("OffsetToImportFileIDs", LDHeader->OffsetToImpid);
+ W.printNumber("LengthOfStringTable", LDHeader->LengthOfStrTbl);
+ W.printHex("OffsetToStringTable", LDHeader->OffsetToStrTbl);
+ };
+
+ if (Obj.is64Bit()) {
+ const LoaderSectionHeader64 *LoaderSec64 =
+ reinterpret_cast<const LoaderSectionHeader64 *>(LoaderSectionAddr);
+ PrintLoadSecHeaderCommon(LoaderSec64);
+ W.printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl);
+ W.printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt);
+ } else {
+ const LoaderSectionHeader32 *LoaderSec32 =
+ reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr);
+ PrintLoadSecHeaderCommon(LoaderSec32);
+ }
+}
+
+const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
+#define ECase(X) \
+ { #X, XCOFF::X }
+ ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT),
+ ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL),
+ ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU),
+ ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG),
+ ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK),
+ ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE),
+ ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL),
+ ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF),
+ ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM),
+ ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM),
+ ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY),
+ ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS),
+ ECase(C_STTLS), ECase(C_EFCN)
+#undef ECase
+};
+
+template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
+void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) {
+ const LoaderSectionHeader *LoadSecHeader =
+ reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
+ const LoaderSectionSymbolEntry *LoadSecSymEntPtr =
+ reinterpret_cast<LoaderSectionSymbolEntry *>(
+ LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()));
+
+ for (uint32_t i = 0; i < LoadSecHeader->NumberOfSymTabEnt;
+ ++i, ++LoadSecSymEntPtr) {
+ if (Error E = Binary::checkOffset(
+ Obj.getMemoryBufferRef(),
+ LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()) +
+ (i * sizeof(LoaderSectionSymbolEntry)),
+ sizeof(LoaderSectionSymbolEntry))) {
+ reportUniqueWarning(std::move(E));
+ return;
+ }
+
+ Expected<StringRef> SymbolNameOrErr =
+ LoadSecSymEntPtr->getSymbolName(LoadSecHeader);
+ if (!SymbolNameOrErr) {
+ reportUniqueWarning(SymbolNameOrErr.takeError());
+ return;
+ }
+
+ DictScope DS(W, "Symbol");
+ W.printString("Name", SymbolNameOrErr.get());
+ W.printHex("Virtual Address", LoadSecSymEntPtr->Value);
+ W.printNumber("SectionNum", LoadSecSymEntPtr->SectionNumber);
+ W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType);
+ W.printEnum("StorageClass",
+ static_cast<uint8_t>(LoadSecSymEntPtr->StorageClass),
+ ArrayRef(SymStorageClass));
+ W.printHex("ImportFileID", LoadSecSymEntPtr->ImportFileID);
+ W.printNumber("ParameterTypeCheck", LoadSecSymEntPtr->ParameterTypeCheck);
+ }
+}
+
+void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) {
+ DictScope DS(W, "Loader Section Symbols");
if (Obj.is64Bit())
- printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
+ printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry64,
+ LoaderSectionHeader64>(LoaderSectionAddr);
else
- printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
+ printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry32,
+ LoaderSectionHeader32>(LoaderSectionAddr);
}
const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
@@ -148,6 +283,176 @@
#undef ECase
};
+// From the XCOFF specification: there are five implicit external symbols, one
+// each for the .text, .data, .bss, .tdata, and .tbss sections. These symbols
+// are referenced from the relocation table entries using symbol table index
+// values 0, 1, 2, -1, and -2, respectively.
+static const char *getImplicitLoaderSectionSymName(int SymIndx) {
+ switch (SymIndx) {
+ default:
+ return "Unkown Symbol Name";
+ case -2:
+ return ".tbss";
+ case -1:
+ return ".tdata";
+ case 0:
+ return ".text";
+ case 1:
+ return ".data";
+ case 2:
+ return ".bss";
+ }
+}
+
+template <typename LoadSectionRelocTy>
+void XCOFFDumper::printLoaderSectionRelocationEntry(
+ LoadSectionRelocTy *LoaderSecRelEntPtr, StringRef SymbolName) {
+ uint16_t Type = LoaderSecRelEntPtr->Type;
+ if (opts::ExpandRelocs) {
+ DictScope DS(W, "Relocation");
+ auto IsRelocationSigned = [](uint8_t Info) {
+ return Info & XCOFF::XR_SIGN_INDICATOR_MASK;
+ };
+ auto IsFixupIndicated = [](uint8_t Info) {
+ return Info & XCOFF::XR_FIXUP_INDICATOR_MASK;
+ };
+ auto GetRelocatedLength = [](uint8_t Info) {
+ // The relocation encodes the bit length being relocated minus 1. Add
+ // back
+ // the 1 to get the actual length being relocated.
+ return (Info & XCOFF::XR_BIASED_LENGTH_MASK) + 1;
+ };
+
+ uint8_t Info = Type >> 8;
+ W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr);
+ W.printNumber("Symbol", SymbolName, LoaderSecRelEntPtr->SymbolIndex);
+ W.printString("IsSigned", IsRelocationSigned(Info) ? "Yes" : "No");
+ W.printNumber("FixupBitValue", IsFixupIndicated(Info) ? 1 : 0);
+ W.printNumber("Length", GetRelocatedLength(Info));
+ W.printEnum("Type", static_cast<uint8_t>(Type),
+ ArrayRef(RelocationTypeNameclass));
+ W.printNumber("SectionNumber", LoaderSecRelEntPtr->SectionNum);
+ } else {
+ W.startLine() << format_hex(LoaderSecRelEntPtr->VirtualAddr,
+ Obj.is64Bit() ? 18 : 10)
+ << " " << format_hex(Type, 6) << " ("
+ << XCOFF::getRelocationTypeString(
+ static_cast<XCOFF::RelocationType>(Type))
+ << ")" << format_decimal(LoaderSecRelEntPtr->SectionNum, 8)
+ << " " << SymbolName << " ("
+ << LoaderSecRelEntPtr->SymbolIndex << ")\n";
+ }
+}
+
+template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
+ typename LoaderSectionRelocationEntry>
+void XCOFFDumper::printLoaderSectionRelocationEntriesHelper(
+ uintptr_t LoaderSectionAddr) {
+ const LoaderSectionHeader *LoaderSec =
+ reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
+ const LoaderSectionRelocationEntry *LoaderSecRelEntPtr =
+ reinterpret_cast<const LoaderSectionRelocationEntry *>(
+ LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt()));
+
+ if (!opts::ExpandRelocs)
+ W.startLine() << center_justify("Vaddr", Obj.is64Bit() ? 18 : 10)
+ << center_justify("Type", 15) << right_justify("SecNum", 8)
+ << center_justify("SymbolName (Index) ", 24) << "\n";
+
+ for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt;
+ ++i, ++LoaderSecRelEntPtr) {
+ StringRef SymbolName;
+ if (LoaderSecRelEntPtr->SymbolIndex >= FirstSymIdxOfLoaderSec) {
+ // Because there are implicit symbol index values (-2, -1, 0, 1, 2),
+ // LoaderSecRelEnt.SymbolIndex - FirstSymIdxOfLoaderSec will get the
+ // real symbol from the symbol table.
+ const uint64_t SymOffset =
+ (LoaderSecRelEntPtr->SymbolIndex - FirstSymIdxOfLoaderSec) *
+ sizeof(LoaderSectionSymbolEntry);
+ const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr =
+ reinterpret_cast<LoaderSectionSymbolEntry *>(
+ LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl()) +
+ SymOffset);
+
+ Expected<StringRef> SymbolNameOrErr =
+ LoaderSecRelSymEntPtr->getSymbolName(LoaderSec);
+ if (!SymbolNameOrErr) {
+ reportUniqueWarning(SymbolNameOrErr.takeError());
+ return;
+ }
+ SymbolName = SymbolNameOrErr.get();
+ } else
+ SymbolName =
+ getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex);
+
+ printLoaderSectionRelocationEntry(LoaderSecRelEntPtr, SymbolName);
+ }
+}
+
+void XCOFFDumper::printLoaderSectionRelocationEntries(
+ uintptr_t LoaderSectionAddr) {
+ DictScope DS(W, "Loader Section Relocations");
+
+ if (Obj.is64Bit())
+ printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader64,
+ LoaderSectionSymbolEntry64,
+ LoaderSectionRelocationEntry64>(
+ LoaderSectionAddr);
+ else
+ printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader32,
+ LoaderSectionSymbolEntry32,
+ LoaderSectionRelocationEntry32>(
+ LoaderSectionAddr);
+}
+
+template <typename T>
+void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const {
+ if (ExceptionSectEnt.getReason())
+ W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr());
+ else {
+ uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex();
+ Expected<StringRef> ErrOrSymbolName = Obj.getSymbolNameByIndex(SymIdx);
+ if (Error E = ErrOrSymbolName.takeError()) {
+ reportUniqueWarning(std::move(E));
+ return;
+ }
+ StringRef SymName = *ErrOrSymbolName;
+
+ W.printNumber("Symbol", SymName, SymIdx);
+ }
+ W.printNumber("LangID", ExceptionSectEnt.getLangID());
+ W.printNumber("Reason", ExceptionSectEnt.getReason());
+}
+
+template <typename T> void XCOFFDumper::printExceptionSectionEntries() const {
+ Expected<ArrayRef<T>> ExceptSectEntsOrErr = Obj.getExceptionEntries<T>();
+ if (Error E = ExceptSectEntsOrErr.takeError()) {
+ reportUniqueWarning(std::move(E));
+ return;
+ }
+ ArrayRef<T> ExceptSectEnts = *ExceptSectEntsOrErr;
+
+ DictScope DS(W, "Exception section");
+ if (ExceptSectEnts.empty())
+ return;
+ for (auto &Ent : ExceptSectEnts)
+ printExceptionSectionEntry(Ent);
+}
+
+void XCOFFDumper::printExceptionSection() {
+ if (Obj.is64Bit())
+ printExceptionSectionEntries<ExceptionSectionEntry64>();
+ else
+ printExceptionSectionEntries<ExceptionSectionEntry32>();
+}
+
+void XCOFFDumper::printRelocations() {
+ if (Obj.is64Bit())
+ printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
+ else
+ printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
+}
+
template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
Expected<StringRef> ErrOrSymbolName =
Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
@@ -164,8 +469,7 @@
W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
W.printNumber("Length", Reloc.getRelocatedLength());
- W.printEnum("Type", (uint8_t)Reloc.Type,
- makeArrayRef(RelocationTypeNameclass));
+ W.printEnum("Type", (uint8_t)Reloc.Type, ArrayRef(RelocationTypeNameclass));
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
@@ -230,10 +534,10 @@
Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
W.printString("Name", FileName);
W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
- makeArrayRef(FileStringType));
+ ArrayRef(FileStringType));
if (Obj.is64Bit()) {
W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
- makeArrayRef(SymAuxType));
+ ArrayRef(SymAuxType));
}
}
@@ -271,14 +575,14 @@
// Print out symbol alignment and type.
W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
- makeArrayRef(CsectSymbolTypeClass));
+ ArrayRef(CsectSymbolTypeClass));
W.printEnum("StorageMappingClass",
static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
- makeArrayRef(CsectStorageMappingClass));
+ ArrayRef(CsectStorageMappingClass));
if (Obj.is64Bit()) {
W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
- makeArrayRef(SymAuxType));
+ ArrayRef(SymAuxType));
} else {
W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
@@ -310,7 +614,7 @@
W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
- makeArrayRef(SymAuxType));
+ ArrayRef(SymAuxType));
}
void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
@@ -335,7 +639,7 @@
W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
- makeArrayRef(SymAuxType));
+ ArrayRef(SymAuxType));
}
void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
@@ -356,7 +660,7 @@
Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
W.printHex("LineNumber", AuxEntPtr->LineNum);
W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
- makeArrayRef(SymAuxType));
+ ArrayRef(SymAuxType));
}
template <typename T>
@@ -368,28 +672,9 @@
W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
if (Obj.is64Bit())
W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
- makeArrayRef(SymAuxType));
+ ArrayRef(SymAuxType));
}
-const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
-#define ECase(X) \
- { #X, XCOFF::X }
- ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT),
- ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL),
- ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU),
- ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG),
- ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK),
- ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE),
- ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL),
- ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF),
- ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM),
- ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM),
- ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY),
- ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS),
- ECase(C_STTLS), ECase(C_EFCN)
-#undef ECase
-};
-
static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
switch (SC) {
case XCOFF::C_EXT:
@@ -447,7 +732,7 @@
ArrayRef<uint8_t>(
reinterpret_cast<const uint8_t *>(AuxAddress),
XCOFF::SymbolTableEntrySize),
- None, XCOFF::SymbolTableEntrySize)
+ std::nullopt, XCOFF::SymbolTableEntrySize)
<< "\n";
}
@@ -475,14 +760,14 @@
W.printString("Section", SectionName);
if (SymbolClass == XCOFF::C_FILE) {
W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
- makeArrayRef(CFileLangIdClass));
+ ArrayRef(CFileLangIdClass));
W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
- makeArrayRef(CFileCpuIdClass));
+ ArrayRef(CFileCpuIdClass));
} else
W.printHex("Type", SymbolEntRef.getSymbolType());
W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
- makeArrayRef(SymStorageClass));
+ ArrayRef(SymStorageClass));
W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
if (NumberOfAuxEntries == 0)
@@ -492,7 +777,7 @@
if (NumberOfAuxEntries > 1)
reportUniqueWarning("the " +
enumToString(static_cast<uint8_t>(SymbolClass),
- makeArrayRef(SymStorageClass)) +
+ ArrayRef(SymStorageClass)) +
" symbol at index " + Twine(SymbolIdx) +
" should not have more than 1 "
"auxiliary entry");
@@ -519,22 +804,13 @@
case XCOFF::C_EXT:
case XCOFF::C_WEAKEXT:
case XCOFF::C_HIDEXT: {
- if (!SymbolEntRef.isFunction() && NumberOfAuxEntries > 1)
- reportUniqueWarning("the non-function " +
- enumToString(static_cast<uint8_t>(SymbolClass),
- makeArrayRef(SymStorageClass)) +
- " symbol at index " + Twine(SymbolIdx) +
- " should have only 1 auxiliary entry, i.e. the CSECT "
- "auxiliary entry");
-
// For 32-bit objects, print the function auxiliary symbol table entry. The
// last one must be a CSECT auxiliary entry.
// For 64-bit objects, both a function auxiliary entry and an exception
// auxiliary entry may appear, print them in the loop and skip printing the
// CSECT auxiliary entry, which will be printed outside the loop.
for (int I = 1; I <= NumberOfAuxEntries; I++) {
- if ((I == NumberOfAuxEntries && !Obj.is64Bit()) ||
- !SymbolEntRef.isFunction())
+ if (I == NumberOfAuxEntries && !Obj.is64Bit())
break;
uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
@@ -921,7 +1197,7 @@
if (Sec.isReservedSectionType())
W.printHex("Flags", "Reserved", SectionType);
else
- W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));
+ W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames));
}
if (opts::SectionRelocations)
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 e1ebbeb..a11de35 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -21,7 +21,6 @@
#include "llvm-readobj.h"
#include "ObjDumper.h"
#include "WindowsResourceDumper.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
#include "llvm/MC/TargetRegistry.h"
@@ -62,11 +61,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -78,9 +80,11 @@
#undef OPTION
};
-class ReadobjOptTable : public opt::OptTable {
+class ReadobjOptTable : public opt::GenericOptTable {
public:
- ReadobjOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+ ReadobjOptTable() : opt::GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
};
enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
@@ -162,6 +166,10 @@
// XCOFF specific options.
static bool XCOFFAuxiliaryHeader;
+static bool XCOFFLoaderSectionHeader;
+static bool XCOFFLoaderSectionSymbol;
+static bool XCOFFLoaderSectionRelocation;
+static bool XCOFFExceptionSection;
OutputStyleTy Output = OutputStyleTy::LLVM;
static std::vector<std::string> InputFilenames;
@@ -302,6 +310,11 @@
// XCOFF specific options.
opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header);
+ opts::XCOFFLoaderSectionHeader = Args.hasArg(OPT_loader_section_header);
+ opts::XCOFFLoaderSectionSymbol = Args.hasArg(OPT_loader_section_symbols);
+ opts::XCOFFLoaderSectionRelocation =
+ Args.hasArg(OPT_loader_section_relocations);
+ opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section);
opts::InputFilenames = Args.getAllArgValues(OPT_INPUT);
}
@@ -357,7 +370,7 @@
toString(std::move(ContentErr));
ObjDumper *Dumper;
- Optional<SymbolComparator> SymComp;
+ std::optional<SymbolComparator> SymComp;
Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer);
if (!DumperOrErr)
reportError(DumperOrErr.takeError(), FileStr);
@@ -395,6 +408,8 @@
if (opts::FileHeaders)
Dumper->printFileHeaders();
+ // Auxiliary header in XOCFF is right after the file header, so print the data
+ // here.
if (Obj.isXCOFF() && opts::XCOFFAuxiliaryHeader)
Dumper->printAuxiliaryHeader();
@@ -502,6 +517,18 @@
if (opts::CGProfile)
Dumper->printCGProfile();
}
+
+ if (Obj.isXCOFF()) {
+ if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol ||
+ opts::XCOFFLoaderSectionRelocation)
+ Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader,
+ opts::XCOFFLoaderSectionSymbol,
+ opts::XCOFFLoaderSectionRelocation);
+
+ if (opts::XCOFFExceptionSection)
+ Dumper->printExceptionSection();
+ }
+
if (opts::PrintStackMap)
Dumper->printStackMap();
if (opts::PrintStackSizes)
@@ -605,7 +632,7 @@
return std::make_unique<ScopedPrinter>(fouts());
}
-int main(int argc, char *argv[]) {
+int llvm_readobj_main(int argc, char **argv) {
InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
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 989cd0a..5a9fe28 100644
--- a/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h
+++ b/src/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -50,6 +50,6 @@
{ #enum, ns::enum }
#define LLVM_READOBJ_ENUM_CLASS_ENT(enum_class, enum) \
- { #enum, std::underlying_type<enum_class>::type(enum_class::enum) }
+ { #enum, std::underlying_type_t<enum_class>(enum_class::enum) }
#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt
index fe6619d3..b1e8fec 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-reduce/CMakeLists.txt
@@ -11,8 +11,10 @@
IRReader
MC
MIRParser
+ Passes
Support
Target
+ TargetParser
TransformUtils
IPO
)
@@ -27,6 +29,7 @@
deltas/ReduceArguments.cpp
deltas/ReduceAttributes.cpp
deltas/ReduceBasicBlocks.cpp
+ deltas/ReduceDIMetadata.cpp
deltas/ReduceFunctionBodies.cpp
deltas/ReduceFunctions.cpp
deltas/ReduceGlobalObjects.cpp
@@ -34,9 +37,13 @@
deltas/ReduceGlobalVarInitializers.cpp
deltas/ReduceGlobalVars.cpp
deltas/ReduceInstructions.cpp
+ deltas/ReduceInstructionFlags.cpp
+ deltas/ReduceInvokes.cpp
deltas/ReduceMetadata.cpp
deltas/ReduceModuleData.cpp
+ deltas/ReduceMemoryOperations.cpp
deltas/ReduceOperandBundles.cpp
+ deltas/ReduceOpcodes.cpp
deltas/ReduceSpecialGlobals.cpp
deltas/ReduceOperands.cpp
deltas/ReduceOperandsSkip.cpp
@@ -48,7 +55,10 @@
deltas/ReduceRegisterMasks.cpp
deltas/ReduceRegisterDefs.cpp
deltas/ReduceRegisterUses.cpp
+ deltas/ReduceUsingSimplifyCFG.cpp
+ deltas/RunIRPasses.cpp
deltas/SimplifyInstructions.cpp
+ deltas/StripDebugInfo.cpp
llvm-reduce.cpp
DEPENDS
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp b/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp
index 5e9ad51..bfe299c 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.cpp
@@ -19,6 +19,7 @@
#include "deltas/ReduceArguments.h"
#include "deltas/ReduceAttributes.h"
#include "deltas/ReduceBasicBlocks.h"
+#include "deltas/ReduceDIMetadata.h"
#include "deltas/ReduceFunctionBodies.h"
#include "deltas/ReduceFunctions.h"
#include "deltas/ReduceGlobalObjects.h"
@@ -26,11 +27,15 @@
#include "deltas/ReduceGlobalVarInitializers.h"
#include "deltas/ReduceGlobalVars.h"
#include "deltas/ReduceIRReferences.h"
+#include "deltas/ReduceInstructionFlags.h"
#include "deltas/ReduceInstructionFlagsMIR.h"
#include "deltas/ReduceInstructions.h"
#include "deltas/ReduceInstructionsMIR.h"
+#include "deltas/ReduceInvokes.h"
+#include "deltas/ReduceMemoryOperations.h"
#include "deltas/ReduceMetadata.h"
#include "deltas/ReduceModuleData.h"
+#include "deltas/ReduceOpcodes.h"
#include "deltas/ReduceOperandBundles.h"
#include "deltas/ReduceOperands.h"
#include "deltas/ReduceOperandsSkip.h"
@@ -39,34 +44,57 @@
#include "deltas/ReduceRegisterMasks.h"
#include "deltas/ReduceRegisterUses.h"
#include "deltas/ReduceSpecialGlobals.h"
+#include "deltas/ReduceUsingSimplifyCFG.h"
#include "deltas/ReduceVirtualRegisters.h"
+#include "deltas/RunIRPasses.h"
#include "deltas/SimplifyInstructions.h"
+#include "deltas/StripDebugInfo.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
+using SmallStringSet = SmallSet<StringRef, 8>;
+
extern cl::OptionCategory LLVMReduceOptions;
-static cl::opt<std::string>
+static cl::list<std::string>
DeltaPasses("delta-passes",
cl::desc("Delta passes to run, separated by commas. By "
"default, run all delta passes."),
- cl::cat(LLVMReduceOptions));
+ cl::cat(LLVMReduceOptions), cl::CommaSeparated);
+
+static cl::list<std::string>
+ SkipDeltaPasses("skip-delta-passes",
+ cl::desc("Delta passes to not run, separated by commas. By "
+ "default, run all delta passes."),
+ cl::cat(LLVMReduceOptions), cl::CommaSeparated);
#define DELTA_PASSES \
do { \
+ DELTA_PASS("strip-debug-info", stripDebugInfoDeltaPass) \
+ DELTA_PASS("functions", reduceFunctionsDeltaPass) \
+ DELTA_PASS("function-bodies", reduceFunctionBodiesDeltaPass) \
DELTA_PASS("special-globals", reduceSpecialGlobalsDeltaPass) \
DELTA_PASS("aliases", reduceAliasesDeltaPass) \
- DELTA_PASS("function-bodies", reduceFunctionBodiesDeltaPass) \
- DELTA_PASS("functions", reduceFunctionsDeltaPass) \
+ DELTA_PASS("ifuncs", reduceIFuncsDeltaPass) \
+ DELTA_PASS("simplify-conditionals-true", reduceConditionalsTrueDeltaPass) \
+ DELTA_PASS("simplify-conditionals-false", reduceConditionalsFalseDeltaPass)\
+ DELTA_PASS("invokes", reduceInvokesDeltaPass) \
+ DELTA_PASS("unreachable-basic-blocks", reduceUnreachableBasicBlocksDeltaPass) \
DELTA_PASS("basic-blocks", reduceBasicBlocksDeltaPass) \
+ DELTA_PASS("simplify-cfg", reduceUsingSimplifyCFGDeltaPass) \
+ DELTA_PASS("function-data", reduceFunctionDataDeltaPass) \
DELTA_PASS("global-values", reduceGlobalValuesDeltaPass) \
DELTA_PASS("global-objects", reduceGlobalObjectsDeltaPass) \
DELTA_PASS("global-initializers", reduceGlobalsInitializersDeltaPass) \
DELTA_PASS("global-variables", reduceGlobalsDeltaPass) \
+ DELTA_PASS("di-metadata", reduceDIMetadataDeltaPass) \
DELTA_PASS("metadata", reduceMetadataDeltaPass) \
+ DELTA_PASS("named-metadata", reduceNamedMetadataDeltaPass) \
DELTA_PASS("arguments", reduceArgumentsDeltaPass) \
DELTA_PASS("instructions", reduceInstructionsDeltaPass) \
DELTA_PASS("simplify-instructions", simplifyInstructionsDeltaPass) \
+ DELTA_PASS("ir-passes", runIRPassesDeltaPass) \
DELTA_PASS("operands-zero", reduceOperandsZeroDeltaPass) \
DELTA_PASS("operands-one", reduceOperandsOneDeltaPass) \
DELTA_PASS("operands-nan", reduceOperandsNaNDeltaPass) \
@@ -75,7 +103,12 @@
DELTA_PASS("operand-bundles", reduceOperandBundesDeltaPass) \
DELTA_PASS("attributes", reduceAttributesDeltaPass) \
DELTA_PASS("module-data", reduceModuleDataDeltaPass) \
- } while (false)
+ DELTA_PASS("opcodes", reduceOpcodesDeltaPass) \
+ DELTA_PASS("volatile", reduceVolatileInstructionsDeltaPass) \
+ DELTA_PASS("atomic-ordering", reduceAtomicOrderingDeltaPass) \
+ DELTA_PASS("syncscopes", reduceAtomicSyncScopesDeltaPass) \
+ DELTA_PASS("instruction-flags", reduceInstructionFlagsDeltaPass) \
+} while (false)
#define DELTA_PASSES_MIR \
do { \
@@ -91,8 +124,12 @@
DELTA_PASS("register-masks", reduceRegisterMasksMIRDeltaPass) \
} while (false)
-static void runAllDeltaPasses(TestRunner &Tester) {
-#define DELTA_PASS(NAME, FUNC) FUNC(Tester);
+static void runAllDeltaPasses(TestRunner &Tester,
+ const SmallStringSet &SkipPass) {
+#define DELTA_PASS(NAME, FUNC) \
+ if (!SkipPass.count(NAME)) { \
+ FUNC(Tester); \
+ }
if (Tester.getProgram().isMIR()) {
DELTA_PASSES_MIR;
} else {
@@ -113,8 +150,10 @@
DELTA_PASSES;
}
#undef DELTA_PASS
- errs() << "unknown pass \"" << PassName << "\"\n";
- exit(1);
+
+ // We should have errored on unrecognized passes before trying to run
+ // anything.
+ llvm_unreachable("unknown delta pass");
}
void llvm::printDeltaPasses(raw_ostream &OS) {
@@ -127,19 +166,59 @@
#undef DELTA_PASS
}
+// Built a set of available delta passes.
+static void collectPassNames(const TestRunner &Tester,
+ SmallStringSet &NameSet) {
+#define DELTA_PASS(NAME, FUNC) NameSet.insert(NAME);
+ if (Tester.getProgram().isMIR()) {
+ DELTA_PASSES_MIR;
+ } else {
+ DELTA_PASSES;
+ }
+#undef DELTA_PASS
+}
+
+/// Verify all requested or skipped passes are valid names, and return them in a
+/// set.
+static SmallStringSet handlePassList(const TestRunner &Tester,
+ const cl::list<std::string> &PassList) {
+ SmallStringSet AllPasses;
+ collectPassNames(Tester, AllPasses);
+
+ SmallStringSet PassSet;
+ for (StringRef PassName : PassList) {
+ if (!AllPasses.count(PassName)) {
+ errs() << "unknown pass \"" << PassName << "\"\n";
+ exit(1);
+ }
+
+ PassSet.insert(PassName);
+ }
+
+ return PassSet;
+}
+
void llvm::runDeltaPasses(TestRunner &Tester, int MaxPassIterations) {
uint64_t OldComplexity = Tester.getProgram().getComplexityScore();
+
+ SmallStringSet RunPassSet, SkipPassSet;
+
+ if (!DeltaPasses.empty())
+ RunPassSet = handlePassList(Tester, DeltaPasses);
+
+ if (!SkipDeltaPasses.empty())
+ SkipPassSet = handlePassList(Tester, SkipDeltaPasses);
+
for (int Iter = 0; Iter < MaxPassIterations; ++Iter) {
if (DeltaPasses.empty()) {
- runAllDeltaPasses(Tester);
+ runAllDeltaPasses(Tester, SkipPassSet);
} else {
- StringRef Passes = DeltaPasses;
- while (!Passes.empty()) {
- auto Split = Passes.split(",");
- runDeltaPassName(Tester, Split.first);
- Passes = Split.second;
+ for (StringRef PassName : DeltaPasses) {
+ if (!SkipPassSet.count(PassName))
+ runDeltaPassName(Tester, PassName);
}
}
+
uint64_t NewComplexity = Tester.getProgram().getComplexityScore();
if (NewComplexity >= OldComplexity)
break;
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.h b/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.h
index b72e560..c1445a7 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/DeltaManager.h
@@ -1,4 +1,4 @@
-//===- DeltaManager.h - Runs Delta Passes to reduce Input -----------------===//
+//===- DeltaManager.h - Runs Delta Passes to reduce Input -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
index b6e78dd..74107ad 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -7,7 +7,11 @@
//===----------------------------------------------------------------------===//
#include "ReducerWorkItem.h"
+#include "TestRunner.h"
+#include "llvm/Analysis/ModuleSummaryAnalysis.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/CodeGen/MIRPrinter.h"
@@ -18,24 +22,39 @@
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/ModuleSummaryIndex.h"
+#include "llvm/IR/Operator.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Utils/Cloning.h"
+#include <optional>
+
+using namespace llvm;
+
+ReducerWorkItem::ReducerWorkItem() = default;
+ReducerWorkItem::~ReducerWorkItem() = default;
extern cl::OptionCategory LLVMReduceOptions;
static cl::opt<std::string> TargetTriple("mtriple",
cl::desc("Set the target triple"),
cl::cat(LLVMReduceOptions));
-void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx, const char *ToolName);
+static cl::opt<bool> TmpFilesAsBitcode(
+ "write-tmp-files-as-bitcode",
+ cl::desc("Always write temporary files as bitcode instead of textual IR"),
+ cl::init(false), cl::cat(LLVMReduceOptions));
static void cloneFrameInfo(
MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI,
@@ -206,8 +225,10 @@
DstMF->CreateMachineBasicBlock(SrcMBB.getBasicBlock());
Src2DstMBB[&SrcMBB] = DstMBB;
- if (SrcMBB.hasAddressTaken())
- DstMBB->setHasAddressTaken();
+ if (SrcMBB.isIRBlockAddressTaken())
+ DstMBB->setAddressTakenIRBlock(SrcMBB.getAddressTakenIRBlock());
+ if (SrcMBB.isMachineBlockAddressTaken())
+ DstMBB->setMachineBlockAddressTaken();
// FIXME: This is not serialized
if (SrcMBB.hasLabelMustBeEmitted())
@@ -233,7 +254,7 @@
SrcMBB.isInlineAsmBrIndirectTarget());
// FIXME: This is not serialized
- if (Optional<uint64_t> Weight = SrcMBB.getIrrLoopHeaderWeight())
+ if (std::optional<uint64_t> Weight = SrcMBB.getIrrLoopHeaderWeight())
DstMBB->setIrrLoopHeaderWeight(*Weight);
}
@@ -380,136 +401,6 @@
InitializeAllAsmParsers();
}
-std::unique_ptr<ReducerWorkItem>
-parseReducerWorkItem(const char *ToolName, StringRef Filename,
- LLVMContext &Ctxt, std::unique_ptr<TargetMachine> &TM,
- bool IsMIR) {
- Triple TheTriple;
-
- auto MMM = std::make_unique<ReducerWorkItem>();
-
- if (IsMIR) {
- initializeTargetInfo();
-
- auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
- if (std::error_code EC = FileOrErr.getError()) {
- WithColor::error(errs(), ToolName) << EC.message() << '\n';
- return nullptr;
- }
-
- std::unique_ptr<MIRParser> MParser =
- createMIRParser(std::move(FileOrErr.get()), Ctxt);
-
- auto SetDataLayout =
- [&](StringRef DataLayoutTargetTriple) -> Optional<std::string> {
- // If we are supposed to override the target triple, do so now.
- 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;
- 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!");
-
- return TM->createDataLayout().getStringRepresentation();
- };
-
- std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
- LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
-
- MMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
- MParser->parseMachineFunctions(*M, *MMM->MMI);
- MMM->M = std::move(M);
- } else {
- SMDiagnostic Err;
- ErrorOr<std::unique_ptr<MemoryBuffer>> MB = MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = MB.getError()) {
- WithColor::error(errs(), ToolName) << Filename << ": " << EC.message() << "\n";
- return nullptr;
- }
-
- if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(),
- (const unsigned char *)(*MB)->getBufferEnd())) {
- std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
- if (!Result) {
- Err.print(ToolName, errs());
- return nullptr;
- }
- MMM->M = std::move(Result);
- } else {
- readBitcode(*MMM, MemoryBufferRef(**MB), Ctxt, ToolName);
-
- if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
- initializeTargetInfo();
- }
- }
- if (verifyReducerWorkItem(*MMM, &errs())) {
- WithColor::error(errs(), ToolName)
- << Filename << " - input module is broken!\n";
- return nullptr;
- }
- return MMM;
-}
-
-std::unique_ptr<ReducerWorkItem>
-cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM) {
- auto CloneMMM = std::make_unique<ReducerWorkItem>();
- if (TM) {
- // We're assuming the Module IR contents are always unchanged by MIR
- // reductions, and can share it as a constant.
- CloneMMM->M = MMM.M;
-
- // MachineModuleInfo contains a lot of other state used during codegen which
- // we won't be using here, but we should be able to ignore it (although this
- // is pretty ugly).
- const LLVMTargetMachine *LLVMTM =
- static_cast<const LLVMTargetMachine *>(TM);
- CloneMMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
-
- for (const Function &F : MMM.getModule()) {
- if (auto *MF = MMM.MMI->getMachineFunction(F))
- CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));
- }
- } else {
- CloneMMM->M = CloneModule(*MMM.M);
- }
- return CloneMMM;
-}
-
-bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
- if (verifyModule(*MMM.M, OS))
- return true;
-
- if (!MMM.MMI)
- return false;
-
- for (const Function &F : MMM.getModule()) {
- if (const MachineFunction *MF = MMM.MMI->getMachineFunction(F)) {
- if (!MF->verify(nullptr, "", /*AbortOnError=*/false))
- return true;
- }
- }
-
- return false;
-}
-
void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
if (MMI) {
printMIR(ROS, *M);
@@ -523,14 +414,77 @@
}
}
-// FIXME: We might want to use a different metric than "number of
-// bytes in serialized IR" to detect non-progress of the main delta
-// loop
-uint64_t ReducerWorkItem::getIRSize() const {
- std::string Str;
- raw_string_ostream SS(Str);
- print(SS, /*AnnotationWriter=*/nullptr);
- return Str.length();
+bool ReducerWorkItem::verify(raw_fd_ostream *OS) const {
+ if (verifyModule(*M, OS))
+ return true;
+
+ if (!MMI)
+ return false;
+
+ for (const Function &F : getModule()) {
+ if (const MachineFunction *MF = MMI->getMachineFunction(F)) {
+ if (!MF->verify(nullptr, "", /*AbortOnError=*/false))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ReducerWorkItem::isReduced(const TestRunner &Test) const {
+ const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode;
+
+ SmallString<128> CurrentFilepath;
+
+ // Write ReducerWorkItem to tmp file
+ int FD;
+ std::error_code EC = sys::fs::createTemporaryFile(
+ "llvm-reduce", isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), FD,
+ CurrentFilepath,
+ UseBitcode && !isMIR() ? sys::fs::OF_None : sys::fs::OF_Text);
+ if (EC) {
+ errs() << "Error making unique filename: " << EC.message() << "!\n";
+ exit(1);
+ }
+
+ ToolOutputFile Out(CurrentFilepath, FD);
+
+ writeOutput(Out.os(), UseBitcode);
+
+ Out.os().close();
+ if (Out.os().has_error()) {
+ errs() << "Error emitting bitcode to file '" << CurrentFilepath
+ << "': " << Out.os().error().message();
+ exit(1);
+ }
+
+ // Current Chunks aren't interesting
+ return Test.run(CurrentFilepath);
+}
+
+std::unique_ptr<ReducerWorkItem>
+ReducerWorkItem::clone(const TargetMachine *TM) const {
+ auto CloneMMM = std::make_unique<ReducerWorkItem>();
+ if (TM) {
+ // We're assuming the Module IR contents are always unchanged by MIR
+ // reductions, and can share it as a constant.
+ CloneMMM->M = M;
+
+ // MachineModuleInfo contains a lot of other state used during codegen which
+ // we won't be using here, but we should be able to ignore it (although this
+ // is pretty ugly).
+ const LLVMTargetMachine *LLVMTM =
+ static_cast<const LLVMTargetMachine *>(TM);
+ CloneMMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
+
+ for (const Function &F : getModule()) {
+ if (auto *MF = MMI->getMachineFunction(F))
+ CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));
+ }
+ } else {
+ CloneMMM->M = CloneModule(*M);
+ }
+ return CloneMMM;
}
/// Try to produce some number that indicates a function is getting smaller /
@@ -605,3 +559,270 @@
return Score;
}
+
+// FIXME: ReduceOperandsSkip has similar function, except it uses larger numbers
+// for more reduced.
+static unsigned classifyReductivePower(const Value *V) {
+ if (auto *C = dyn_cast<ConstantData>(V)) {
+ if (C->isNullValue())
+ return 0;
+ if (C->isOneValue())
+ return 1;
+ if (isa<UndefValue>(V))
+ return 2;
+ return 3;
+ }
+
+ if (isa<GlobalValue>(V))
+ return 4;
+
+ // TODO: Account for expression size
+ if (isa<ConstantExpr>(V))
+ return 5;
+
+ if (isa<Constant>(V))
+ return 1;
+
+ if (isa<Argument>(V))
+ return 6;
+
+ if (isa<Instruction>(V))
+ return 7;
+
+ return 0;
+}
+
+// TODO: Additional flags and attributes may be complexity reducing. If we start
+// adding flags and attributes, they could have negative cost.
+static uint64_t computeIRComplexityScoreImpl(const Function &F) {
+ uint64_t Score = 1; // Count the function itself
+ SmallVector<std::pair<unsigned, MDNode *>> MDs;
+
+ AttributeList Attrs = F.getAttributes();
+ for (AttributeSet AttrSet : Attrs)
+ Score += AttrSet.getNumAttributes();
+
+ for (const BasicBlock &BB : F) {
+ ++Score;
+
+ for (const Instruction &I : BB) {
+ ++Score;
+
+ if (const auto *OverflowOp = dyn_cast<OverflowingBinaryOperator>(&I)) {
+ if (OverflowOp->hasNoUnsignedWrap())
+ ++Score;
+ if (OverflowOp->hasNoSignedWrap())
+ ++Score;
+ } else if (const auto *GEP = dyn_cast<GEPOperator>(&I)) {
+ if (GEP->isInBounds())
+ ++Score;
+ } else if (const auto *ExactOp = dyn_cast<PossiblyExactOperator>(&I)) {
+ if (ExactOp->isExact())
+ ++Score;
+ } else if (const auto *FPOp = dyn_cast<FPMathOperator>(&I)) {
+ FastMathFlags FMF = FPOp->getFastMathFlags();
+ if (FMF.allowReassoc())
+ ++Score;
+ if (FMF.noNaNs())
+ ++Score;
+ if (FMF.noInfs())
+ ++Score;
+ if (FMF.noSignedZeros())
+ ++Score;
+ if (FMF.allowReciprocal())
+ ++Score;
+ if (FMF.allowContract())
+ ++Score;
+ if (FMF.approxFunc())
+ ++Score;
+ }
+
+ for (const Value *Operand : I.operands()) {
+ ++Score;
+ Score += classifyReductivePower(Operand);
+ }
+
+ I.getAllMetadata(MDs);
+ Score += MDs.size();
+ MDs.clear();
+ }
+ }
+
+ return Score;
+}
+
+uint64_t ReducerWorkItem::computeIRComplexityScore() const {
+ uint64_t Score = 0;
+
+ const Module &M = getModule();
+ Score += M.named_metadata_size();
+
+ SmallVector<std::pair<unsigned, MDNode *>, 32> GlobalMetadata;
+ for (const GlobalVariable &GV : M.globals()) {
+ ++Score;
+
+ if (GV.hasInitializer())
+ Score += classifyReductivePower(GV.getInitializer());
+
+ // TODO: Account for linkage?
+
+ GV.getAllMetadata(GlobalMetadata);
+ Score += GlobalMetadata.size();
+ GlobalMetadata.clear();
+ }
+
+ for (const GlobalAlias &GA : M.aliases())
+ Score += classifyReductivePower(GA.getAliasee());
+
+ for (const GlobalIFunc &GI : M.ifuncs())
+ Score += classifyReductivePower(GI.getResolver());
+
+ for (const Function &F : M)
+ Score += computeIRComplexityScoreImpl(F);
+
+ return Score;
+}
+
+void ReducerWorkItem::writeOutput(raw_ostream &OS, bool EmitBitcode) const {
+ // Requesting bitcode emission with mir is nonsense, so just ignore it.
+ if (EmitBitcode && !isMIR())
+ writeBitcode(OS);
+ else
+ print(OS, /*AnnotationWriter=*/nullptr);
+}
+
+void ReducerWorkItem::readBitcode(MemoryBufferRef Data, LLVMContext &Ctx,
+ StringRef ToolName) {
+ Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);
+ if (!IF) {
+ WithColor::error(errs(), ToolName) << IF.takeError();
+ exit(1);
+ }
+ BitcodeModule BM = IF->Mods[0];
+ Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
+ Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);
+ if (!LI || !MOrErr) {
+ WithColor::error(errs(), ToolName) << IF.takeError();
+ exit(1);
+ }
+ LTOInfo = std::make_unique<BitcodeLTOInfo>(*LI);
+ M = std::move(MOrErr.get());
+}
+
+void ReducerWorkItem::writeBitcode(raw_ostream &OutStream) const {
+ if (LTOInfo && LTOInfo->IsThinLTO && LTOInfo->EnableSplitLTOUnit) {
+ PassBuilder PB;
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+ ModulePassManager MPM;
+ MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr));
+ MPM.run(*M, MAM);
+ } else {
+ std::unique_ptr<ModuleSummaryIndex> Index;
+ if (LTOInfo && LTOInfo->HasSummary) {
+ ProfileSummaryInfo PSI(*M);
+ Index = std::make_unique<ModuleSummaryIndex>(
+ buildModuleSummaryIndex(*M, nullptr, &PSI));
+ }
+ WriteBitcodeToFile(getModule(), OutStream, Index.get());
+ }
+}
+
+std::pair<std::unique_ptr<ReducerWorkItem>, bool>
+llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename,
+ LLVMContext &Ctxt,
+ std::unique_ptr<TargetMachine> &TM, bool IsMIR) {
+ bool IsBitcode = false;
+ Triple TheTriple;
+
+ auto MMM = std::make_unique<ReducerWorkItem>();
+
+ if (IsMIR) {
+ initializeTargetInfo();
+
+ auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
+ if (std::error_code EC = FileOrErr.getError()) {
+ WithColor::error(errs(), ToolName) << EC.message() << '\n';
+ return {nullptr, false};
+ }
+
+ std::unique_ptr<MIRParser> MParser =
+ createMIRParser(std::move(FileOrErr.get()), Ctxt);
+
+ auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
+ StringRef OldDLStr) -> std::optional<std::string> {
+ // If we are supposed to override the target triple, do so now.
+ 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!");
+
+ return TM->createDataLayout().getStringRepresentation();
+ };
+
+ std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
+ LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
+
+ MMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
+ MParser->parseMachineFunctions(*M, *MMM->MMI);
+ MMM->M = std::move(M);
+ } else {
+ SMDiagnostic Err;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ if (std::error_code EC = MB.getError()) {
+ WithColor::error(errs(), ToolName)
+ << Filename << ": " << EC.message() << "\n";
+ return {nullptr, false};
+ }
+
+ if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(),
+ (const unsigned char *)(*MB)->getBufferEnd())) {
+ std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
+ if (!Result) {
+ Err.print(ToolName.data(), errs());
+ return {nullptr, false};
+ }
+ MMM->M = std::move(Result);
+ } else {
+ IsBitcode = true;
+ MMM->readBitcode(MemoryBufferRef(**MB), Ctxt, ToolName);
+
+ if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
+ initializeTargetInfo();
+ }
+ }
+ if (MMM->verify(&errs())) {
+ WithColor::error(errs(), ToolName)
+ << Filename << " - input module is broken!\n";
+ return {nullptr, false};
+ }
+ return {std::move(MMM), IsBitcode};
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.h b/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.h
index 7dd5786..dc11322 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/ReducerWorkItem.h
@@ -1,4 +1,4 @@
-//===- ReducerWorkItem.h - Wrapper for Module and MachineFunction ---------===//
+//===- ReducerWorkItem.h - Wrapper for Module -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -9,14 +9,17 @@
#ifndef LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
#define LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/Module.h"
-#include "llvm/IR/ModuleSummaryIndex.h"
-#include "llvm/Target/TargetMachine.h"
+#include <memory>
-using namespace llvm;
+namespace llvm {
+class LLVMContext;
+class MachineModuleInfo;
+class MemoryBufferRef;
+class raw_ostream;
+class TargetMachine;
+class TestRunner;
+struct BitcodeLTOInfo;
class ReducerWorkItem {
public:
@@ -24,31 +27,44 @@
std::unique_ptr<BitcodeLTOInfo> LTOInfo;
std::unique_ptr<MachineModuleInfo> MMI;
+ ReducerWorkItem();
+ ~ReducerWorkItem();
+ ReducerWorkItem(ReducerWorkItem &) = delete;
+ ReducerWorkItem(ReducerWorkItem &&) = default;
+
bool isMIR() const { return MMI != nullptr; }
+ LLVMContext &getContext() {
+ return M->getContext();
+ }
+
+ Module &getModule() { return *M; }
const Module &getModule() const { return *M; }
+ operator Module &() const { return *M; }
void print(raw_ostream &ROS, void *p = nullptr) const;
- operator Module &() const { return *M; }
+ bool verify(raw_fd_ostream *OS) const;
+ std::unique_ptr<ReducerWorkItem> clone(const TargetMachine *TM) const;
/// Return a number to indicate whether there was any reduction progress.
uint64_t getComplexityScore() const {
- return isMIR() ? computeMIRComplexityScore() : getIRSize();
+ return isMIR() ? computeMIRComplexityScore() : computeIRComplexityScore();
}
+ void writeOutput(raw_ostream &OS, bool EmitBitcode) const;
+ void readBitcode(MemoryBufferRef Data, LLVMContext &Ctx, StringRef ToolName);
+ void writeBitcode(raw_ostream &OutStream) const;
+
+ bool isReduced(const TestRunner &Test) const;
+
private:
+ uint64_t computeIRComplexityScore() const;
uint64_t computeMIRComplexityScore() const;
- uint64_t getIRSize() const;
};
-std::unique_ptr<ReducerWorkItem>
-parseReducerWorkItem(const char *ToolName, StringRef Filename,
- LLVMContext &Ctxt, std::unique_ptr<TargetMachine> &TM,
- bool IsMIR);
-
-std::unique_ptr<ReducerWorkItem>
-cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM);
-
-bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS);
+std::pair<std::unique_ptr<ReducerWorkItem>, bool>
+parseReducerWorkItem(StringRef ToolName, StringRef Filename, LLVMContext &Ctxt,
+ std::unique_ptr<TargetMachine> &TM, bool IsMIR);
+} // namespace llvm
#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.cpp b/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.cpp
index 691790d..8a61aae 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.cpp
@@ -8,22 +8,31 @@
#include "TestRunner.h"
#include "ReducerWorkItem.h"
-#include "llvm/CodeGen/MachineFunction.h"
+#include "deltas/Utils.h"
+#include "llvm/Support/WithColor.h"
using namespace llvm;
TestRunner::TestRunner(StringRef TestName,
const std::vector<std::string> &TestArgs,
std::unique_ptr<ReducerWorkItem> Program,
- std::unique_ptr<TargetMachine> TM, const char *ToolName)
+ std::unique_ptr<TargetMachine> TM, StringRef ToolName,
+ StringRef OutputName, bool InputIsBitcode,
+ bool OutputBitcode)
: TestName(TestName), ToolName(ToolName), TestArgs(TestArgs),
- Program(std::move(Program)), TM(std::move(TM)) {
+ Program(std::move(Program)), TM(std::move(TM)),
+ OutputFilename(OutputName), InputIsBitcode(InputIsBitcode),
+ EmitBitcode(OutputBitcode) {
assert(this->Program && "Initialized with null program?");
}
+static constexpr std::array<std::optional<StringRef>, 3> DefaultRedirects = {
+ StringRef()};
+static constexpr std::array<std::optional<StringRef>, 3> NullRedirects;
+
/// Runs the interestingness test, passes file to be tested as first argument
/// and other specified test arguments after that.
-int TestRunner::run(StringRef Filename) {
+int TestRunner::run(StringRef Filename) const {
std::vector<StringRef> ProgramArgs;
ProgramArgs.push_back(TestName);
@@ -33,22 +42,33 @@
ProgramArgs.push_back(Filename);
std::string ErrMsg;
- int Result = sys::ExecuteAndWait(
- TestName, ProgramArgs, /*Env=*/None, /*Redirects=*/None,
- /*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
+
+ int Result =
+ sys::ExecuteAndWait(TestName, ProgramArgs, /*Env=*/std::nullopt,
+ Verbose ? DefaultRedirects : NullRedirects,
+ /*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
if (Result < 0) {
Error E = make_error<StringError>("Error running interesting-ness test: " +
ErrMsg,
inconvertibleErrorCode());
- errs() << toString(std::move(E));
+ WithColor::error(errs(), ToolName) << toString(std::move(E)) << '\n';
exit(1);
}
return !Result;
}
-void TestRunner::setProgram(std::unique_ptr<ReducerWorkItem> P) {
- assert(P && "Setting null program?");
- Program = std::move(P);
+void TestRunner::writeOutput(StringRef Message) {
+ std::error_code EC;
+ raw_fd_ostream Out(OutputFilename, EC,
+ EmitBitcode && !Program->isMIR() ? sys::fs::OF_None
+ : sys::fs::OF_Text);
+ if (EC) {
+ errs() << "Error opening output file: " << EC.message() << "!\n";
+ exit(1);
+ }
+
+ Program->writeOutput(Out, EmitBitcode);
+ errs() << Message << OutputFilename << '\n';
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h b/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h
index 6d7dd7a..136cd80 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/TestRunner.h
@@ -28,27 +28,40 @@
public:
TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs,
std::unique_ptr<ReducerWorkItem> Program,
- std::unique_ptr<TargetMachine> TM, const char *ToolName);
+ std::unique_ptr<TargetMachine> TM, StringRef ToolName,
+ StringRef OutputFilename, bool InputIsBitcode, bool OutputBitcode);
/// Runs the interesting-ness test for the specified file
/// @returns 0 if test was successful, 1 if otherwise
- int run(StringRef Filename);
+ int run(StringRef Filename) const;
/// Returns the most reduced version of the original testcase
ReducerWorkItem &getProgram() const { return *Program; }
- void setProgram(std::unique_ptr<ReducerWorkItem> P);
+ void setProgram(std::unique_ptr<ReducerWorkItem> &&P) {
+ assert(P && "Setting null program?");
+ Program = std::move(P);
+ }
const TargetMachine *getTargetMachine() const { return TM.get(); }
- const char *getToolName() const { return ToolName; }
+ StringRef getToolName() const { return ToolName; }
+
+ void writeOutput(StringRef Message);
+
+ bool inputIsBitcode() const {
+ return InputIsBitcode;
+ }
private:
StringRef TestName;
- const char *ToolName;
+ StringRef ToolName;
const std::vector<std::string> &TestArgs;
std::unique_ptr<ReducerWorkItem> Program;
std::unique_ptr<TargetMachine> TM;
+ StringRef OutputFilename;
+ const bool InputIsBitcode;
+ bool EmitBitcode;
};
} // namespace llvm
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 55b96d8..9bdfb66 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.cpp
@@ -14,9 +14,11 @@
#include "Delta.h"
#include "ReducerWorkItem.h"
+#include "TestRunner.h"
+#include "Utils.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -26,7 +28,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/ThreadPool.h"
-#include "llvm/Support/ToolOutputFile.h"
#include <fstream>
#include <set>
@@ -44,115 +45,56 @@
cl::desc("Number of times to divide chunks prior to first test"),
cl::cat(LLVMReduceOptions));
-static cl::opt<bool> TmpFilesAsBitcode(
- "write-tmp-files-as-bitcode",
- cl::desc("Write temporary files as bitcode, instead of textual IR"),
- cl::init(false), cl::cat(LLVMReduceOptions));
-
#ifdef LLVM_ENABLE_THREADS
static cl::opt<unsigned> NumJobs(
"j",
cl::desc("Maximum number of threads to use to process chunks. Set to 1 to "
- "disables parallelism."),
+ "disable parallelism."),
cl::init(1), cl::cat(LLVMReduceOptions));
#else
unsigned NumJobs = 1;
#endif
-void writeOutput(ReducerWorkItem &M, llvm::StringRef Message);
-
-void writeBitcode(ReducerWorkItem &M, raw_ostream &OutStream);
-
-void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx,
- const char *ToolName);
-
-bool isReduced(ReducerWorkItem &M, TestRunner &Test,
- SmallString<128> &CurrentFilepath) {
- // Write ReducerWorkItem to tmp file
- int FD;
- std::error_code EC = sys::fs::createTemporaryFile(
- "llvm-reduce", M.isMIR() ? "mir" : (TmpFilesAsBitcode ? "bc" : "ll"), FD,
- CurrentFilepath);
- if (EC) {
- errs() << "Error making unique filename: " << EC.message() << "!\n";
- exit(1);
- }
-
- if (TmpFilesAsBitcode) {
- llvm::raw_fd_ostream OutStream(FD, true);
- writeBitcode(M, OutStream);
- OutStream.close();
- if (OutStream.has_error()) {
- errs() << "Error emitting bitcode to file '" << CurrentFilepath << "'!\n";
- sys::fs::remove(CurrentFilepath);
- exit(1);
- }
- bool Res = Test.run(CurrentFilepath);
- sys::fs::remove(CurrentFilepath);
- return Res;
- }
- ToolOutputFile Out(CurrentFilepath, FD);
- M.print(Out.os(), /*AnnotationWriter=*/nullptr);
- Out.os().close();
- if (Out.os().has_error()) {
- errs() << "Error emitting bitcode to file '" << CurrentFilepath << "'!\n";
- exit(1);
- }
-
- // Current Chunks aren't interesting
- return Test.run(CurrentFilepath);
-}
-
-/// Counts the amount of lines for a given file
-static int getLines(StringRef Filepath) {
- int Lines = 0;
- std::string CurrLine;
- std::ifstream FileStream{std::string(Filepath)};
-
- while (std::getline(FileStream, CurrLine))
- ++Lines;
-
- return Lines;
-}
-
/// Splits Chunks in half and prints them.
/// If unable to split (when chunk size is 1) returns false.
static bool increaseGranularity(std::vector<Chunk> &Chunks) {
- errs() << "Increasing granularity...";
+ if (Verbose)
+ errs() << "Increasing granularity...";
std::vector<Chunk> NewChunks;
- bool SplitOne = false;
+ bool SplitAny = false;
- for (auto &C : Chunks) {
+ for (Chunk C : Chunks) {
if (C.End - C.Begin == 0)
NewChunks.push_back(C);
else {
int Half = (C.Begin + C.End) / 2;
NewChunks.push_back({C.Begin, Half});
NewChunks.push_back({Half + 1, C.End});
- SplitOne = true;
+ SplitAny = true;
}
}
- if (SplitOne) {
+ if (SplitAny) {
Chunks = NewChunks;
- errs() << "Success! New Chunks:\n";
- for (auto C : Chunks) {
- errs() << '\t';
- C.print();
- errs() << '\n';
+ if (Verbose) {
+ errs() << "Success! " << NewChunks.size() << " New Chunks:\n";
+ for (auto C : Chunks) {
+ errs() << '\t';
+ C.print();
+ errs() << '\n';
+ }
}
}
- return SplitOne;
+ return SplitAny;
}
// Check if \p ChunkToCheckForUninterestingness is interesting. Returns the
// modified module if the chunk resulted in a reduction.
-template <typename FuncType>
static std::unique_ptr<ReducerWorkItem>
-CheckChunk(Chunk &ChunkToCheckForUninterestingness,
- std::unique_ptr<ReducerWorkItem> Clone, TestRunner &Test,
- FuncType ExtractChunksFromModule,
- std::set<Chunk> &UninterestingChunks,
- std::vector<Chunk> &ChunksStillConsideredInteresting) {
+CheckChunk(const Chunk ChunkToCheckForUninterestingness,
+ std::unique_ptr<ReducerWorkItem> Clone, const TestRunner &Test,
+ ReductionFunc ExtractChunksFromModule,
+ const DenseSet<Chunk> &UninterestingChunks,
+ const std::vector<Chunk> &ChunksStillConsideredInteresting) {
// Take all of ChunksStillConsideredInteresting chunks, except those we've
// already deemed uninteresting (UninterestingChunks) but didn't remove
// from ChunksStillConsideredInteresting yet, and additionally ignore
@@ -162,8 +104,8 @@
UninterestingChunks.size() - 1);
copy_if(ChunksStillConsideredInteresting, std::back_inserter(CurrentChunks),
[&](const Chunk &C) {
- return !UninterestingChunks.count(C) &&
- C != ChunkToCheckForUninterestingness;
+ return C != ChunkToCheckForUninterestingness &&
+ !UninterestingChunks.count(C);
});
// Generate Module with only Targets inside Current Chunks
@@ -171,41 +113,46 @@
ExtractChunksFromModule(O, *Clone);
// Some reductions may result in invalid IR. Skip such reductions.
- if (verifyReducerWorkItem(*Clone, &errs())) {
+ if (Clone->verify(&errs())) {
if (AbortOnInvalidReduction) {
- errs() << "Invalid reduction\n";
+ errs() << "Invalid reduction, aborting.\n";
+ Clone->print(errs());
exit(1);
}
- errs() << " **** WARNING | reduction resulted in invalid module, "
- "skipping\n";
+ if (Verbose) {
+ errs() << " **** WARNING | reduction resulted in invalid module, "
+ "skipping\n";
+ }
return nullptr;
}
- errs() << "Ignoring: ";
- ChunkToCheckForUninterestingness.print();
- for (const Chunk &C : UninterestingChunks)
- C.print();
-
- SmallString<128> CurrentFilepath;
- if (!isReduced(*Clone, Test, CurrentFilepath)) {
- // Program became non-reduced, so this chunk appears to be interesting.
+ if (Verbose) {
+ errs() << "Ignoring: ";
+ ChunkToCheckForUninterestingness.print();
+ for (const Chunk &C : UninterestingChunks)
+ C.print();
errs() << "\n";
+ }
+
+ if (!Clone->isReduced(Test)) {
+ // Program became non-reduced, so this chunk appears to be interesting.
+ if (Verbose)
+ errs() << "\n";
return nullptr;
}
return Clone;
}
-template <typename FuncType>
-SmallString<0> ProcessChunkFromSerializedBitcode(
- Chunk &ChunkToCheckForUninterestingness, TestRunner &Test,
- FuncType ExtractChunksFromModule, std::set<Chunk> &UninterestingChunks,
- std::vector<Chunk> &ChunksStillConsideredInteresting,
- SmallString<0> &OriginalBC, std::atomic<bool> &AnyReduced) {
+static SmallString<0> ProcessChunkFromSerializedBitcode(
+ const Chunk ChunkToCheckForUninterestingness, const TestRunner &Test,
+ ReductionFunc ExtractChunksFromModule,
+ const DenseSet<Chunk> &UninterestingChunks,
+ ArrayRef<Chunk> ChunksStillConsideredInteresting, StringRef OriginalBC,
+ std::atomic<bool> &AnyReduced) {
LLVMContext Ctx;
auto CloneMMM = std::make_unique<ReducerWorkItem>();
- auto Data = MemoryBufferRef(StringRef(OriginalBC.data(), OriginalBC.size()),
- "<bc file>");
- readBitcode(*CloneMMM, Data, Ctx, Test.getToolName());
+ MemoryBufferRef Data(OriginalBC, "<bc file>");
+ CloneMMM->readBitcode(Data, Ctx, Test.getToolName());
SmallString<0> Result;
if (std::unique_ptr<ReducerWorkItem> ChunkResult =
@@ -213,27 +160,32 @@
Test, ExtractChunksFromModule, UninterestingChunks,
ChunksStillConsideredInteresting)) {
raw_svector_ostream BCOS(Result);
- writeBitcode(*ChunkResult, BCOS);
+ ChunkResult->writeBitcode(BCOS);
// Communicate that the task reduced a chunk.
AnyReduced = true;
}
return Result;
}
+using SharedTaskQueue = std::deque<std::shared_future<SmallString<0>>>;
+
+static void waitAndDiscardResultsBarrier(SharedTaskQueue &TaskQueue) {
+ while (!TaskQueue.empty()) {
+ auto &Future = TaskQueue.front();
+ Future.wait();
+ TaskQueue.pop_front();
+ }
+}
+
/// Runs the Delta Debugging algorithm, splits the code into chunks and
/// reduces the amount of chunks that are considered interesting by the
/// given test. The number of chunks is determined by a preliminary run of the
/// reduction pass where no change must be made to the module.
-void llvm::runDeltaPass(TestRunner &Test,
- ReductionFunc ExtractChunksFromModule) {
- assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
+void llvm::runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
+ StringRef Message) {
+ assert(!Test.getProgram().verify(&errs()) &&
"input module is broken before making changes");
-
- SmallString<128> CurrentFilepath;
- if (!isReduced(Test.getProgram(), Test, CurrentFilepath)) {
- errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
- exit(1);
- }
+ errs() << "*** " << Message << "...\n";
int Targets;
{
@@ -245,24 +197,26 @@
ExtractChunksFromModule(Counter, Test.getProgram());
Targets = Counter.count();
- assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
+ assert(!Test.getProgram().verify(&errs()) &&
"input module is broken after counting chunks");
- assert(isReduced(Test.getProgram(), Test, CurrentFilepath) &&
+ assert(Test.getProgram().isReduced(Test) &&
"input module no longer interesting after counting chunks");
#ifndef NDEBUG
// Make sure that the number of chunks does not change as we reduce.
- std::vector<Chunk> NoChunks;
+ std::vector<Chunk> NoChunks = {{0, INT_MAX}};
Oracle NoChunksCounter(NoChunks);
std::unique_ptr<ReducerWorkItem> Clone =
- cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine());
+ Test.getProgram().clone(Test.getTargetMachine());
ExtractChunksFromModule(NoChunksCounter, *Clone);
assert(Targets == NoChunksCounter.count() &&
"number of chunks changes when reducing");
#endif
}
if (!Targets) {
- errs() << "\nNothing to reduce\n";
+ if (Verbose)
+ errs() << "\nNothing to reduce\n";
+ errs() << "----------------------------\n";
return;
}
@@ -283,17 +237,17 @@
do {
FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity = false;
- std::set<Chunk> UninterestingChunks;
+ DenseSet<Chunk> UninterestingChunks;
// When running with more than one thread, serialize the original bitcode
// to OriginalBC.
SmallString<0> OriginalBC;
if (NumJobs > 1) {
raw_svector_ostream BCOS(OriginalBC);
- writeBitcode(Test.getProgram(), BCOS);
+ Test.getProgram().writeBitcode(BCOS);
}
- std::deque<std::shared_future<SmallString<0>>> TaskQueue;
+ SharedTaskQueue TaskQueue;
for (auto I = ChunksStillConsideredInteresting.rbegin(),
E = ChunksStillConsideredInteresting.rend();
I != E; ++I) {
@@ -317,14 +271,12 @@
// LLVMContext object. If a task reduces the input, serialize the result
// back in the corresponding Result element.
for (unsigned J = 0; J < NumInitialTasks; ++J) {
+ Chunk ChunkToCheck = *(I + J);
TaskQueue.emplace_back(ChunkThreadPool.async(
- [J, I, &Test, &ExtractChunksFromModule, &UninterestingChunks,
- &ChunksStillConsideredInteresting, &OriginalBC, &AnyReduced]() {
- return ProcessChunkFromSerializedBitcode(
- *(I + J), Test, ExtractChunksFromModule,
- UninterestingChunks, ChunksStillConsideredInteresting,
- OriginalBC, AnyReduced);
- }));
+ ProcessChunkFromSerializedBitcode, ChunkToCheck, std::ref(Test),
+ ExtractChunksFromModule, UninterestingChunks,
+ ChunksStillConsideredInteresting, OriginalBC,
+ std::ref(AnyReduced)));
}
// Start processing results of the queued tasks. We wait for the first
@@ -343,46 +295,49 @@
if (Res.empty()) {
unsigned NumScheduledTasks = NumChunksProcessed + TaskQueue.size();
if (!AnyReduced && I + NumScheduledTasks != E) {
- Chunk &ChunkToCheck = *(I + NumScheduledTasks);
+ Chunk ChunkToCheck = *(I + NumScheduledTasks);
TaskQueue.emplace_back(ChunkThreadPool.async(
- [&Test, &ExtractChunksFromModule, &UninterestingChunks,
- &ChunksStillConsideredInteresting, &OriginalBC,
- &ChunkToCheck, &AnyReduced]() {
- return ProcessChunkFromSerializedBitcode(
- ChunkToCheck, Test, ExtractChunksFromModule,
- UninterestingChunks, ChunksStillConsideredInteresting,
- OriginalBC, AnyReduced);
- }));
+ ProcessChunkFromSerializedBitcode, ChunkToCheck,
+ std::ref(Test), ExtractChunksFromModule, UninterestingChunks,
+ ChunksStillConsideredInteresting, OriginalBC,
+ std::ref(AnyReduced)));
}
continue;
}
Result = std::make_unique<ReducerWorkItem>();
- auto Data = MemoryBufferRef(StringRef(Res.data(), Res.size()),
- "<bc file>");
- readBitcode(*Result, Data, Test.getProgram().M->getContext(),
- Test.getToolName());
+ MemoryBufferRef Data(StringRef(Res), "<bc file>");
+ Result->readBitcode(Data, Test.getProgram().M->getContext(),
+ Test.getToolName());
break;
}
+
+ // If we broke out of the loop, we still need to wait for everything to
+ // avoid race access to the chunk set.
+ //
+ // TODO: Create a way to kill remaining items we're ignoring; they could
+ // take a long time.
+ waitAndDiscardResultsBarrier(TaskQueue);
+
// Forward I to the last chunk processed in parallel.
I += NumChunksProcessed - 1;
} else {
- Result = CheckChunk(
- *I,
- cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine()),
- Test, ExtractChunksFromModule, UninterestingChunks,
- ChunksStillConsideredInteresting);
+ Result =
+ CheckChunk(*I, Test.getProgram().clone(Test.getTargetMachine()),
+ Test, ExtractChunksFromModule, UninterestingChunks,
+ ChunksStillConsideredInteresting);
}
if (!Result)
continue;
- Chunk &ChunkToCheckForUninterestingness = *I;
+ const Chunk ChunkToCheckForUninterestingness = *I;
FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity = true;
UninterestingChunks.insert(ChunkToCheckForUninterestingness);
ReducedProgram = std::move(Result);
- errs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath) << "\n";
- writeOutput(*ReducedProgram, "Saved new best reduction to ");
+
+ // FIXME: Report meaningful progress info
+ Test.writeOutput(" **** SUCCESS | Saved new best reduction to ");
}
// Delete uninteresting chunks
erase_if(ChunksStillConsideredInteresting,
@@ -396,5 +351,7 @@
// If we reduced the testcase replace it
if (ReducedProgram)
Test.setProgram(std::move(ReducedProgram));
- errs() << "Couldn't increase anymore.\n";
+ if (Verbose)
+ errs() << "Couldn't increase anymore.\n";
+ errs() << "----------------------------\n";
}
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 76aaf25..5b60ea6 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h
@@ -1,4 +1,4 @@
-//===- Delta.h - Delta Debugging Algorithm Implementation -----------------===//
+//===- Delta.h - Delta Debugging Algorithm Implementation -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -15,14 +15,18 @@
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_DELTA_H
#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_DELTA_H
-#include "TestRunner.h"
+#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 {
+class TestRunner;
+
struct Chunk {
int Begin;
int End;
@@ -31,10 +35,10 @@
bool contains(int Index) const { return Index >= Begin && Index <= End; }
void print() const {
- errs() << "[" << Begin;
+ errs() << '[' << Begin;
if (End - Begin != 0)
- errs() << "," << End;
- errs() << "]";
+ errs() << ',' << End;
+ errs() << ']';
}
/// Operator when populating CurrentChunks in Generic Delta Pass
@@ -42,12 +46,39 @@
return C1.Begin != C2.Begin || C1.End != C2.End;
}
+ friend bool operator==(const Chunk &C1, const Chunk &C2) {
+ return C1.Begin == C2.Begin && C1.End == C2.End;
+ }
+
/// Operator used for sets
friend bool operator<(const Chunk &C1, const Chunk &C2) {
return std::tie(C1.Begin, C1.End) < std::tie(C2.Begin, C2.End);
}
};
+template<>
+struct DenseMapInfo<Chunk> {
+ static inline Chunk getEmptyKey() {
+ return {DenseMapInfo<int>::getEmptyKey(),
+ DenseMapInfo<int>::getEmptyKey()};
+ }
+
+ static inline Chunk getTombstoneKey() {
+ return {DenseMapInfo<int>::getTombstoneKey(),
+ DenseMapInfo<int>::getTombstoneKey()};
+ }
+
+ static unsigned getHashValue(const Chunk Val) {
+ std::pair<int, int> PairVal = std::make_pair(Val.Begin, Val.End);
+ return DenseMapInfo<std::pair<int, int>>::getHashValue(PairVal);
+ }
+
+ static bool isEqual(const Chunk LHS, const Chunk RHS) {
+ return LHS == RHS;
+ }
+};
+
+
/// Provides opaque interface for querying into ChunksToKeep without having to
/// actually understand what is going on.
class Oracle {
@@ -105,7 +136,8 @@
///
/// Other implementations of the Delta Debugging algorithm can also be found in
/// the CReduce, Delta, and Lithium projects.
-void runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule);
+void runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
+ StringRef Message);
} // namespace llvm
#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp
index cdcd426..d889b3e 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp
@@ -13,15 +13,17 @@
#include "ReduceAliases.h"
#include "Delta.h"
+#include "Utils.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalValue.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
/// Removes all aliases aren't inside any of the
/// desired Chunks.
-static void extractAliasesFromModule(Oracle &O, Module &Program) {
- for (auto &GA : make_early_inc_range(Program.aliases())) {
+static void extractAliasesFromModule(Oracle &O, ReducerWorkItem &Program) {
+ for (auto &GA : make_early_inc_range(Program.getModule().aliases())) {
if (!O.shouldKeep()) {
GA.replaceAllUsesWith(GA.getAliasee());
GA.eraseFromParent();
@@ -29,8 +31,21 @@
}
}
+static void extractIFuncsFromModule(Oracle &O, Module &Program) {
+ std::vector<GlobalIFunc *> IFuncs;
+ for (GlobalIFunc &GI : Program.ifuncs()) {
+ if (!O.shouldKeep())
+ IFuncs.push_back(&GI);
+ }
+
+ if (!IFuncs.empty())
+ lowerGlobalIFuncUsersAsGlobalCtor(Program, IFuncs);
+}
+
void llvm::reduceAliasesDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Aliases ...\n";
- runDeltaPass(Test, extractAliasesFromModule);
- errs() << "----------------------------\n";
+ runDeltaPass(Test, extractAliasesFromModule, "Reducing Aliases");
+}
+
+void llvm::reduceIFuncsDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, extractIFuncsFromModule, "Reducing Ifuncs");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.h
index 0660efe..404677d 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAliases.h
@@ -1,4 +1,4 @@
-//===- ReduceAliases.h - Specialized Delta Pass ---------------------------===//
+//===- ReduceAliases.h - Specialized Delta Pass -----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -18,6 +18,7 @@
namespace llvm {
void reduceAliasesDeltaPass(TestRunner &Test);
+void reduceIFuncsDeltaPass(TestRunner &Test);
} // namespace llvm
#endif
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 45b5525..10bbc64 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp
@@ -56,7 +56,8 @@
/// Removes out-of-chunk arguments from functions, and modifies their calls
/// accordingly. It also removes allocations of out-of-chunk arguments.
-static void extractArgumentsFromModule(Oracle &O, Module &Program) {
+static void extractArgumentsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
std::vector<Argument *> InitArgsToKeep;
std::vector<Function *> Funcs;
// Get inside-chunk arguments, as well as their parent function
@@ -119,6 +120,5 @@
}
void llvm::reduceArgumentsDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Arguments...\n";
- runDeltaPass(Test, extractArgumentsFromModule);
+ runDeltaPass(Test, extractArgumentsFromModule, "Reducing Arguments");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.h
index 228409d..5adcfe8 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceArguments.h
@@ -1,4 +1,4 @@
-//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
+//===- ReduceArguments.h - Specialized Delta Pass ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
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 7b87088..df87ce7 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp
@@ -42,142 +42,115 @@
namespace {
-using AttrPtrVecTy = std::vector<const Attribute *>;
-using AttrPtrIdxVecVecTy = std::pair<unsigned, AttrPtrVecTy>;
-using AttrPtrVecVecTy = SmallVector<AttrPtrIdxVecVecTy, 3>;
-
/// Given ChunksToKeep, produce a map of global variables/functions/calls
/// and indexes of attributes to be preserved for each of them.
class AttributeRemapper : public InstVisitor<AttributeRemapper> {
Oracle &O;
+ LLVMContext &Context;
public:
- DenseMap<GlobalVariable *, AttrPtrVecTy> GlobalVariablesToRefine;
- DenseMap<Function *, AttrPtrVecVecTy> FunctionsToRefine;
- DenseMap<CallBase *, AttrPtrVecVecTy> CallsToRefine;
-
- explicit AttributeRemapper(Oracle &O) : O(O) {}
+ AttributeRemapper(Oracle &O, LLVMContext &C) : O(O), Context(C) {}
void visitModule(Module &M) {
- for (GlobalVariable &GV : M.getGlobalList())
+ for (GlobalVariable &GV : M.globals())
visitGlobalVariable(GV);
}
void visitGlobalVariable(GlobalVariable &GV) {
// Global variables only have one attribute set.
- const AttributeSet &AS = GV.getAttributes();
- if (AS.hasAttributes())
- visitAttributeSet(AS, GlobalVariablesToRefine[&GV]);
- }
-
- void visitFunction(Function &F) {
- if (F.getIntrinsicID() != Intrinsic::not_intrinsic)
- return; // We can neither add nor remove attributes from intrinsics.
- visitAttributeList(F.getAttributes(), FunctionsToRefine[&F]);
- }
-
- void visitCallBase(CallBase &I) {
- visitAttributeList(I.getAttributes(), CallsToRefine[&I]);
- }
-
- void visitAttributeList(const AttributeList &AL,
- AttrPtrVecVecTy &AttributeSetsToPreserve) {
- assert(AttributeSetsToPreserve.empty() && "Should not be sharing vectors.");
- AttributeSetsToPreserve.reserve(AL.getNumAttrSets());
- for (unsigned SetIdx : AL.indexes()) {
- AttrPtrIdxVecVecTy AttributesToPreserve;
- AttributesToPreserve.first = SetIdx;
- visitAttributeSet(AL.getAttributes(AttributesToPreserve.first),
- AttributesToPreserve.second);
- if (!AttributesToPreserve.second.empty())
- AttributeSetsToPreserve.emplace_back(std::move(AttributesToPreserve));
+ AttributeSet AS = GV.getAttributes();
+ if (AS.hasAttributes()) {
+ AttrBuilder AttrsToPreserve(Context);
+ visitAttributeSet(AS, AttrsToPreserve);
+ GV.setAttributes(AttributeSet::get(Context, AttrsToPreserve));
}
}
- void visitAttributeSet(const AttributeSet &AS,
- AttrPtrVecTy &AttrsToPreserve) {
- assert(AttrsToPreserve.empty() && "Should not be sharing vectors.");
- AttrsToPreserve.reserve(AS.getNumAttributes());
- for (const Attribute &A : AS)
- if (O.shouldKeep())
- AttrsToPreserve.emplace_back(&A);
- }
-};
-
-struct AttributeCounter : public InstVisitor<AttributeCounter> {
- /// How many features (in this case, attributes) did we count, total?
- int AttributeCount = 0;
-
- void visitModule(Module &M) {
- for (GlobalVariable &GV : M.getGlobalList())
- visitGlobalVariable(GV);
- }
-
- void visitGlobalVariable(GlobalVariable &GV) {
- // Global variables only have one attribute set.
- visitAttributeSet(GV.getAttributes());
- }
-
void visitFunction(Function &F) {
- if (F.getIntrinsicID() != Intrinsic::not_intrinsic)
- return; // We can neither add nor remove attributes from intrinsics.
- visitAttributeList(F.getAttributes());
+ // We can neither add nor remove attributes from intrinsics.
+ if (F.getIntrinsicID() == Intrinsic::not_intrinsic)
+ F.setAttributes(visitAttributeList(F.getAttributes()));
}
- void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); }
-
- void visitAttributeList(const AttributeList &AL) {
- for (const AttributeSet &AS : AL)
- visitAttributeSet(AS);
+ void visitCallBase(CallBase &CB) {
+ CB.setAttributes(visitAttributeList(CB.getAttributes()));
}
- void visitAttributeSet(const AttributeSet &AS) {
- AttributeCount += AS.getNumAttributes();
+ AttributeSet visitAttributeIndex(AttributeList AL, unsigned Index) {
+ AttrBuilder AttributesToPreserve(Context);
+ visitAttributeSet(AL.getAttributes(Index), AttributesToPreserve);
+
+ if (AttributesToPreserve.attrs().empty())
+ return {};
+ return AttributeSet::get(Context, AttributesToPreserve);
+ }
+
+ AttributeList visitAttributeList(AttributeList AL) {
+ SmallVector<std::pair<unsigned, AttributeSet>> NewAttrList;
+ NewAttrList.reserve(AL.getNumAttrSets());
+
+ for (unsigned SetIdx : AL.indexes()) {
+ if (SetIdx == AttributeList::FunctionIndex)
+ continue;
+
+ AttributeSet AttrSet = visitAttributeIndex(AL, SetIdx);
+ if (AttrSet.hasAttributes())
+ NewAttrList.emplace_back(SetIdx, AttrSet);
+ }
+
+ // FIXME: It's ridiculous that indexes() doesn't give us the correct order
+ // for contructing a new AttributeList. Special case the function index so
+ // we don't have to sort.
+ AttributeSet FnAttrSet =
+ visitAttributeIndex(AL, AttributeList::FunctionIndex);
+ if (FnAttrSet.hasAttributes())
+ NewAttrList.emplace_back(AttributeList::FunctionIndex, FnAttrSet);
+
+ return AttributeList::get(Context, NewAttrList);
+ }
+
+ void visitAttributeSet(const AttributeSet &AS, AttrBuilder &AttrsToPreserve) {
+ // Optnone requires noinline, so removing noinline requires removing the
+ // pair.
+ Attribute NoInline = AS.getAttribute(Attribute::NoInline);
+ bool RemoveNoInline = false;
+ if (NoInline.isValid()) {
+ RemoveNoInline = !O.shouldKeep();
+ if (!RemoveNoInline)
+ AttrsToPreserve.addAttribute(NoInline);
+ }
+
+ for (Attribute A : AS) {
+ if (A.isEnumAttribute()) {
+ Attribute::AttrKind Kind = A.getKindAsEnum();
+ if (Kind == Attribute::NoInline)
+ continue;
+
+ if (RemoveNoInline && Kind == Attribute::OptimizeNone)
+ continue;
+
+ // TODO: Could only remove this if there are no constrained calls in the
+ // function.
+ if (Kind == Attribute::StrictFP) {
+ AttrsToPreserve.addAttribute(A);
+ continue;
+ }
+ }
+
+ if (O.shouldKeep())
+ AttrsToPreserve.addAttribute(A);
+ }
}
};
} // namespace
-AttributeSet
-convertAttributeRefToAttributeSet(LLVMContext &C,
- ArrayRef<const Attribute *> Attributes) {
- AttrBuilder B(C);
- for (const Attribute *A : Attributes)
- B.addAttribute(*A);
- return AttributeSet::get(C, B);
-}
-
-AttributeList convertAttributeRefVecToAttributeList(
- LLVMContext &C, ArrayRef<AttrPtrIdxVecVecTy> AttributeSets) {
- std::vector<std::pair<unsigned, AttributeSet>> SetVec;
- SetVec.reserve(AttributeSets.size());
-
- transform(AttributeSets, std::back_inserter(SetVec),
- [&C](const AttrPtrIdxVecVecTy &V) {
- return std::make_pair(
- V.first, convertAttributeRefToAttributeSet(C, V.second));
- });
-
- llvm::sort(SetVec, llvm::less_first()); // All values are unique.
-
- return AttributeList::get(C, SetVec);
-}
-
/// Removes out-of-chunk attributes from module.
-static void extractAttributesFromModule(Oracle &O, Module &Program) {
- AttributeRemapper R(O);
- R.visit(Program);
-
- LLVMContext &C = Program.getContext();
- for (const auto &I : R.GlobalVariablesToRefine)
- I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second));
- for (const auto &I : R.FunctionsToRefine)
- I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
- for (const auto &I : R.CallsToRefine)
- I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
+static void extractAttributesFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ AttributeRemapper R(O, WorkItem.getContext());
+ R.visit(WorkItem.getModule());
}
void llvm::reduceAttributesDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Attributes...\n";
- runDeltaPass(Test, extractAttributesFromModule);
+ runDeltaPass(Test, extractAttributesFromModule, "Reducing Attributes");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h
index 375e764..a2e9955 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h
@@ -1,4 +1,4 @@
-//===- ReduceAttributes.h - Specialized Delta Pass ------------------------===//
+//===- ReduceAttributes.h - Specialized Delta Pass --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp
index 520a45c..6858dac 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp
@@ -22,24 +22,49 @@
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
+
#include <vector>
+#define DEBUG_TYPE "llvm-reduce"
+
using namespace llvm;
/// Replaces BB Terminator with one that only contains Chunk BBs
static void replaceBranchTerminator(BasicBlock &BB,
- const DenseSet<BasicBlock *> &BBsToKeep) {
+ const DenseSet<BasicBlock *> &BBsToDelete) {
auto *Term = BB.getTerminator();
std::vector<BasicBlock *> ChunkSuccessors;
- for (auto *Succ : successors(&BB))
- if (BBsToKeep.count(Succ))
+ for (auto *Succ : successors(&BB)) {
+ if (!BBsToDelete.count(Succ))
ChunkSuccessors.push_back(Succ);
+ }
// BB only references Chunk BBs
if (ChunkSuccessors.size() == Term->getNumSuccessors())
return;
- bool IsBranch = isa<BranchInst>(Term) || isa<InvokeInst>(Term);
+ bool IsBranch = isa<BranchInst>(Term);
+ if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Term)) {
+ LandingPadInst *LP = Invoke->getLandingPadInst();
+ // Remove landingpad instruction if the containing block isn't used by other
+ // invokes.
+ if (none_of(LP->getParent()->users(), [Invoke](User *U) {
+ return U != Invoke && isa<InvokeInst>(U);
+ })) {
+ LP->replaceAllUsesWith(getDefaultValue(LP->getType()));
+ LP->eraseFromParent();
+ } else if (!ChunkSuccessors.empty() &&
+ ChunkSuccessors[0] == LP->getParent()) {
+ // If the selected successor is the landing pad, clear the chunk
+ // successors to avoid creating a regular branch to the landing pad which
+ // would result in invalid IR.
+ ChunkSuccessors.clear();
+ }
+ IsBranch = true;
+ }
+
Value *Address = nullptr;
if (auto *IndBI = dyn_cast<IndirectBrInst>(Term))
Address = IndBI->getAddress();
@@ -48,18 +73,6 @@
Term->eraseFromParent();
if (ChunkSuccessors.empty()) {
- // Scan forward in BB list to try find a block that is kept.
- Function &F = *BB.getParent();
- Function::iterator FI = BB.getIterator();
- FI++;
- while (FI != F.end()) {
- auto &FIB = *FI;
- if (BBsToKeep.count(&FIB) && !isa<PHINode>(FIB.begin())) {
- BranchInst::Create(&FIB, &BB);
- return;
- }
- FI++;
- }
// If that fails then resort to replacing with a ret.
auto *FnRetTy = BB.getParent()->getReturnType();
ReturnInst::Create(BB.getContext(),
@@ -84,70 +97,121 @@
/// replace with something)
static void
removeUninterestingBBsFromSwitch(SwitchInst &SwInst,
- const DenseSet<BasicBlock *> &BBsToKeep) {
- if (!BBsToKeep.count(SwInst.getDefaultDest())) {
- auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType();
- ReturnInst::Create(SwInst.getContext(),
- FnRetTy->isVoidTy() ? nullptr : getDefaultValue(FnRetTy),
- SwInst.getParent());
- SwInst.eraseFromParent();
- } else
- for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
- auto Case = SwInst.case_begin() + I;
- if (!BBsToKeep.count(Case->getCaseSuccessor())) {
- SwInst.removeCase(Case);
- --I;
- --E;
- }
+ const DenseSet<BasicBlock *> &BBsToDelete) {
+ for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
+ auto Case = SwInst.case_begin() + I;
+ if (BBsToDelete.count(Case->getCaseSuccessor())) {
+ SwInst.removeCase(Case);
+ --I;
+ --E;
}
+ }
+
+ if (BBsToDelete.count(SwInst.getDefaultDest())) {
+ if (SwInst.getNumCases() == 0) {
+ auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType();
+ Value *RetValue =
+ FnRetTy->isVoidTy() ? nullptr : getDefaultValue(FnRetTy);
+ ReturnInst::Create(SwInst.getContext(), RetValue, SwInst.getParent());
+ SwInst.eraseFromParent();
+ return;
+ }
+
+ // Replace the default dest with one of the other cases
+ auto Case = SwInst.case_begin();
+
+ BasicBlock *NewDefault = Case->getCaseSuccessor();
+ SwInst.setDefaultDest(NewDefault);
+
+ for (PHINode &SuccPHI : NewDefault->phis()) {
+ SuccPHI.addIncoming(SuccPHI.getIncomingValueForBlock(SwInst.getParent()),
+ SwInst.getParent());
+ }
+ }
}
/// Removes out-of-chunk arguments from functions, and modifies their calls
/// accordingly. It also removes allocations of out-of-chunk arguments.
-static void extractBasicBlocksFromModule(Oracle &O, Module &Program) {
- DenseSet<BasicBlock *> BBsToKeep;
+static void extractBasicBlocksFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ DenseSet<BasicBlock *> BBsToDelete;
+ df_iterator_default_set<BasicBlock *> Reachable;
- SmallVector<BasicBlock *> BBsToDelete;
- for (auto &F : Program) {
- for (auto &BB : F) {
- if (O.shouldKeep())
- BBsToKeep.insert(&BB);
- else {
- BBsToDelete.push_back(&BB);
- // Remove out-of-chunk BB from successor phi nodes
- for (auto *Succ : successors(&BB))
- Succ->removePredecessor(&BB);
- }
+ for (auto &F : WorkItem.getModule()) {
+ if (F.empty())
+ continue;
+
+ BasicBlock &Entry = F.getEntryBlock();
+ for (auto *BB : depth_first_ext(&Entry, Reachable))
+ (void)BB;
+
+ // Skip any function with unreachable blocks. It's somewhat difficult to
+ // avoid producing invalid IR without deleting them.
+ //
+ // We also do not want to unconditionally delete them, as doing so would
+ // break the invariant of changing the number of chunks during counting.
+
+ const bool HasUnreachableBlocks = Reachable.size() != F.size();
+ Reachable.clear();
+
+ if (HasUnreachableBlocks) {
+ LLVM_DEBUG(dbgs() << "Skipping function with unreachable blocks\n");
+ continue;
}
- }
- // Replace terminators that reference out-of-chunk BBs
- for (auto &F : Program)
- for (auto &BB : F) {
+ for (BasicBlock &BB : F) {
+ if (&BB != &Entry && !O.shouldKeep())
+ BBsToDelete.insert(&BB);
+ }
+
+ // Replace terminators that reference out-of-chunk BBs
+ for (BasicBlock &BB : F) {
if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator()))
- removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep);
+ removeUninterestingBBsFromSwitch(*SwInst, BBsToDelete);
else
- replaceBranchTerminator(BB, BBsToKeep);
+ replaceBranchTerminator(BB, BBsToDelete);
}
- // Replace out-of-chunk switch uses
- for (auto &BB : BBsToDelete) {
- // Instructions might be referenced in other BBs
- for (auto &I : *BB)
- I.replaceAllUsesWith(getDefaultValue(I.getType()));
- if (BB->getParent()->size() == 1) {
- // this is the last basic block of the function, thus we must also make
- // sure to remove comdat and set linkage to external
- auto F = BB->getParent();
- F->deleteBody();
- F->setComdat(nullptr);
- } else {
- BB->eraseFromParent();
- }
+ // Cleanup any blocks that are now dead after eliminating this set. This
+ // will likely be larger than the number of blocks the oracle told us to
+ // delete.
+ EliminateUnreachableBlocks(F);
+ BBsToDelete.clear();
}
}
void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Basic Blocks...\n";
- runDeltaPass(Test, extractBasicBlocksFromModule);
+ runDeltaPass(Test, extractBasicBlocksFromModule, "Reducing Basic Blocks");
+}
+
+static void removeUnreachableBasicBlocksFromModule(Oracle &O,
+ ReducerWorkItem &WorkItem) {
+ std::vector<BasicBlock *> DeadBlocks;
+ df_iterator_default_set<BasicBlock *> Reachable;
+
+ for (Function &F : WorkItem.getModule()) {
+ if (F.empty())
+ continue;
+
+ // Mark all reachable blocks.
+ for (BasicBlock *BB : depth_first_ext(&F, Reachable))
+ (void)BB;
+
+ if (Reachable.size() != F.size() && !O.shouldKeep()) {
+ for (BasicBlock &BB : F) {
+ if (!Reachable.count(&BB))
+ DeadBlocks.push_back(&BB);
+ }
+
+ // Delete the dead blocks.
+ DeleteDeadBlocks(DeadBlocks, nullptr, /*KeepOneInputPHIs*/ false);
+ DeadBlocks.clear();
+ }
+
+ Reachable.clear();
+ }
+}
+
+void llvm::reduceUnreachableBasicBlocksDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, removeUnreachableBasicBlocksFromModule,
+ "Removing Unreachable Basic Blocks");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.h
index 4938552..a090d67 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.h
@@ -1,4 +1,4 @@
-//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
+//===- ReduceArguments.h - Specialized Delta Pass ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
//
// This file implements a function which calls the Generic Delta pass in order
-// to reduce uninteresting Arguments from defined functions.
+// to reduce uninteresting BasicBlocks from defined functions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEBASICBLOCKS_H
@@ -19,6 +19,7 @@
namespace llvm {
void reduceBasicBlocksDeltaPass(TestRunner &Test);
+void reduceUnreachableBasicBlocksDeltaPass(TestRunner &Test);
} // namespace llvm
#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp
new file mode 100644
index 0000000..bbd928a
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp
@@ -0,0 +1,104 @@
+//===- ReduceDIMetadata.cpp - Specialized Delta pass for DebugInfo --------===//
+//
+// 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 two functions used by the Generic Delta Debugging
+// Algorithm, which are used to reduce DebugInfo metadata nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceDIMetadata.h"
+#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>
+
+using namespace llvm;
+
+using MDNodeList = SmallVector<MDNode *>;
+
+void identifyUninterestingMDNodes(Oracle &O, MDNodeList &MDs) {
+ SetVector<std::tuple<MDNode *, size_t, MDNode *>> Tuples;
+ std::vector<MDNode *> ToLook;
+ SetVector<MDNode *> Visited;
+
+ // Start by looking at the attachments we collected
+ for (const auto &NMD : MDs)
+ if (NMD)
+ ToLook.push_back(NMD);
+
+ while (!ToLook.empty()) {
+ MDNode *MD = ToLook.back();
+ ToLook.pop_back();
+
+ if (Visited.count(MD))
+ continue;
+
+ // Determine if the current MDNode is DebugInfo
+ if (DINode *DIM = dyn_cast_or_null<DINode>(MD)) {
+ // Scan operands and record attached tuples
+ for (size_t I = 0; I < DIM->getNumOperands(); ++I)
+ if (MDTuple *MDT = dyn_cast_or_null<MDTuple>(DIM->getOperand(I)))
+ if (!Visited.count(MDT) && MDT->getNumOperands())
+ Tuples.insert({DIM, I, MDT});
+ }
+
+ // Add all of the operands of the current node to the loop's todo list.
+ for (Metadata *Op : MD->operands())
+ if (MDNode *OMD = dyn_cast_or_null<MDNode>(Op))
+ ToLook.push_back(OMD);
+
+ Visited.insert(MD);
+ }
+
+ for (auto &T : Tuples) {
+ auto [DbgNode, OpIdx, Tup] = T;
+ // Remove the operands of the tuple that are not in the desired chunks.
+ SmallVector<Metadata *, 16> TN;
+ for (size_t I = 0; I < Tup->getNumOperands(); ++I) {
+ // Ignore any operands that are not DebugInfo metadata nodes.
+ if (isa_and_nonnull<DINode>(Tup->getOperand(I)))
+ // Don't add uninteresting operands to the tuple.
+ if (!O.shouldKeep())
+ continue;
+
+ TN.push_back(Tup->getOperand(I));
+ }
+ if (TN.size() != Tup->getNumOperands())
+ DbgNode->replaceOperandWith(OpIdx, DbgNode->get(DbgNode->getContext(), TN));
+ }
+}
+
+static void extractDIMetadataFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
+ MDNodeList MDs;
+ // Collect all !dbg metadata attachments.
+ for (const auto &DC : Program.debug_compile_units())
+ if (DC)
+ MDs.push_back(DC);
+ for (GlobalVariable &GV : Program.globals())
+ GV.getMetadata(llvm::LLVMContext::MD_dbg, MDs);
+ for (Function &F : Program.functions()) {
+ F.getMetadata(llvm::LLVMContext::MD_dbg, MDs);
+ for (Instruction &I : instructions(F))
+ if (auto *DI = I.getMetadata(llvm::LLVMContext::MD_dbg))
+ MDs.push_back(DI);
+ }
+ identifyUninterestingMDNodes(O, MDs);
+}
+
+void llvm::reduceDIMetadataDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, extractDIMetadataFromModule, "Reducing DIMetadata");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.h
new file mode 100644
index 0000000..379c14a
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.h
@@ -0,0 +1,23 @@
+//===- ReduceMetadata.h - 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 two functions used by the Generic Delta Debugging
+// Algorithm, which are used to reduce Metadata nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDIMETADATA_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDIMETADATA_H
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceDIMetadataDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp
index 63dd2f0..21875ba 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp
@@ -13,24 +13,50 @@
#include "ReduceFunctionBodies.h"
#include "Delta.h"
+#include "Utils.h"
#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Instructions.h"
using namespace llvm;
/// Removes all the bodies of defined functions that aren't inside any of the
/// desired Chunks.
-static void extractFunctionBodiesFromModule(Oracle &O, Module &Program) {
+static void extractFunctionBodiesFromModule(Oracle &O,
+ ReducerWorkItem &WorkItem) {
// Delete out-of-chunk function bodies
- std::vector<Function *> FuncDefsToReduce;
- for (auto &F : Program)
- if (!F.isDeclaration() && !O.shouldKeep()) {
+ for (auto &F : WorkItem.getModule()) {
+ if (!F.isDeclaration() && !hasAliasUse(F) && !O.shouldKeep()) {
F.deleteBody();
F.setComdat(nullptr);
}
+ }
}
void llvm::reduceFunctionBodiesDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Function Bodies...\n";
- runDeltaPass(Test, extractFunctionBodiesFromModule);
- errs() << "----------------------------\n";
+ runDeltaPass(Test, extractFunctionBodiesFromModule,
+ "Reducing Function Bodies");
+}
+
+static void reduceFunctionData(Oracle &O, ReducerWorkItem &WorkItem) {
+ for (Function &F : WorkItem.getModule()) {
+ if (F.hasPersonalityFn()) {
+ if (none_of(F,
+ [](const BasicBlock &BB) {
+ return BB.isEHPad() || isa<ResumeInst>(BB.getTerminator());
+ }) &&
+ !O.shouldKeep()) {
+ F.setPersonalityFn(nullptr);
+ }
+ }
+
+ if (F.hasPrefixData() && !O.shouldKeep())
+ F.setPrefixData(nullptr);
+
+ if (F.hasPrologueData() && !O.shouldKeep())
+ F.setPrologueData(nullptr);
+ }
+}
+
+void llvm::reduceFunctionDataDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceFunctionData, "Reducing Function Data");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.h
index bfe701b..ae738fb 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.h
@@ -1,4 +1,4 @@
-//===- ReduceFunctionBodies.h - Specialized Delta Pass --------------------===//
+//===- ReduceFunctionBodies.h - Specialized Delta Pass ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -18,6 +18,7 @@
namespace llvm {
void reduceFunctionBodiesDeltaPass(TestRunner &Test);
+void reduceFunctionDataDeltaPass(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 346e2c3..05127ec 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
@@ -16,8 +16,8 @@
#include "Delta.h"
#include "Utils.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Instructions.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <iterator>
#include <vector>
@@ -25,33 +25,38 @@
/// Removes all the Defined Functions
/// that aren't inside any of the desired Chunks.
-static void extractFunctionsFromModule(Oracle &O, Module &Program) {
+static void extractFunctionsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
// Record all out-of-chunk functions.
- std::vector<std::reference_wrapper<Function>> FuncsToRemove;
- copy_if(Program.functions(), std::back_inserter(FuncsToRemove),
- [&O](Function &F) {
- // Intrinsics don't have function bodies that are useful to
- // reduce. Additionally, intrinsics may have additional operand
- // constraints. But, do drop intrinsics that are not referenced.
- return (!F.isIntrinsic() || F.use_empty()) && !O.shouldKeep();
- });
+ SmallPtrSet<Constant *, 8> FuncsToRemove;
+ for (Function &F : Program.functions()) {
+ // Intrinsics don't have function bodies that are useful to
+ // reduce. Additionally, intrinsics may have additional operand
+ // constraints. But, do drop intrinsics that are not referenced.
+ if ((!F.isIntrinsic() || F.use_empty()) && !hasAliasOrBlockAddressUse(F) &&
+ !O.shouldKeep())
+ FuncsToRemove.insert(&F);
+ }
+
+ removeFromUsedLists(Program, [&FuncsToRemove](Constant *C) {
+ return FuncsToRemove.count(C);
+ });
// Then, drop body of each of them. We want to batch this and do nothing else
// here so that minimal number of remaining exteranal uses will remain.
- for (Function &F : FuncsToRemove)
- F.dropAllReferences();
+ for (Constant *F : FuncsToRemove)
+ F->dropAllReferences();
// And finally, we can actually delete them.
- for (Function &F : FuncsToRemove) {
+ for (Constant *F : FuncsToRemove) {
// Replace all *still* remaining uses with the default value.
- F.replaceAllUsesWith(getDefaultValue(F.getType()));
+ F->replaceAllUsesWith(getDefaultValue(F->getType()));
// And finally, fully drop it.
- F.eraseFromParent();
+ cast<Function>(F)->eraseFromParent();
}
}
void llvm::reduceFunctionsDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Functions...\n";
- runDeltaPass(Test, extractFunctionsFromModule);
- errs() << "----------------------------\n";
+ runDeltaPass(Test, extractFunctionsFromModule, "Reducing Functions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.h
index f5bc83b..d3ff0d9 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceFunctions.h
@@ -1,4 +1,4 @@
-//===- ReduceFunctions.h - Specialized Delta Pass -------------------------===//
+//===- ReduceFunctions.h - Specialized Delta Pass ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.cpp
index 33ec3ae..1d1463a 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.cpp
@@ -17,16 +17,19 @@
return GO.getAlign().has_value();
}
-static void reduceGOs(Oracle &O, Module &Program) {
- for (auto &GO : Program.global_objects()) {
+static bool shouldReduceComdat(GlobalObject &GO) { return GO.hasComdat(); }
+
+static void reduceGOs(Oracle &O, ReducerWorkItem &Program) {
+ for (auto &GO : Program.getModule().global_objects()) {
if (shouldReduceSection(GO) && !O.shouldKeep())
GO.setSection("");
if (shouldReduceAlign(GO) && !O.shouldKeep())
GO.setAlignment(MaybeAlign());
+ if (shouldReduceComdat(GO) && !O.shouldKeep())
+ GO.setComdat(nullptr);
}
}
void llvm::reduceGlobalObjectsDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing GlobalObjects...\n";
- runDeltaPass(Test, reduceGOs);
+ runDeltaPass(Test, reduceGOs, "Reducing GlobalObjects");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.h
index 7224b9b..35c38a9 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalObjects.h
@@ -1,4 +1,4 @@
-//===- ReduceGlobalObjects.h ----------------------------------------------===//
+//===- ReduceGlobalObjects.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.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp
index 26a3cbd..470d5ba 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp
@@ -37,8 +37,8 @@
return GV.isThreadLocal();
}
-static void reduceGVs(Oracle &O, Module &Program) {
- for (auto &GV : Program.global_values()) {
+static void reduceGVs(Oracle &O, ReducerWorkItem &Program) {
+ for (auto &GV : Program.getModule().global_values()) {
if (shouldReduceDSOLocal(GV) && !O.shouldKeep())
GV.setDSOLocal(false);
if (shouldReduceVisibility(GV) && !O.shouldKeep()) {
@@ -58,6 +58,5 @@
}
void llvm::reduceGlobalValuesDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing GlobalValues...\n";
- runDeltaPass(Test, reduceGVs);
+ runDeltaPass(Test, reduceGVs, "Reducing GlobalValues");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.h
index ea32a6c..19c0707 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.h
@@ -1,4 +1,4 @@
-//===- ReduceGlobalValues.h - Specialized Delta Pass ----------------------===//
+//===- ReduceGlobalValues.h - Specialized Delta Pass ------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp
index c9e4d9f..4c71252 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp
@@ -18,9 +18,9 @@
using namespace llvm;
/// Removes all the Initialized GVs that aren't inside the desired Chunks.
-static void extractGVsFromModule(Oracle &O, Module &Program) {
+static void extractGVsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
// Drop initializers of out-of-chunk GVs
- for (auto &GV : Program.globals())
+ for (auto &GV : WorkItem.getModule().globals())
if (GV.hasInitializer() && !O.shouldKeep()) {
GV.setInitializer(nullptr);
GV.setLinkage(GlobalValue::LinkageTypes::ExternalLinkage);
@@ -29,6 +29,5 @@
}
void llvm::reduceGlobalsInitializersDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing GVs initializers...\n";
- runDeltaPass(Test, extractGVsFromModule);
+ runDeltaPass(Test, extractGVsFromModule, "Reducing GV Initializers");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h
index 0f5f22a..318b29b 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.h
@@ -1,4 +1,4 @@
-//===- reduceGlobalsInitializersDeltaPass.h - Specialized Delta Pass ------===//
+//===- ReduceGlobalVarInitializers.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.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
index 908c984..b448081 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
@@ -14,51 +14,46 @@
#include "ReduceGlobalVars.h"
#include "Utils.h"
#include "llvm/IR/Constants.h"
-#include <set>
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
+static bool shouldAlwaysKeep(const GlobalVariable &GV) {
+ return GV.getName() == "llvm.used" || GV.getName() == "llvm.compiler.used";
+}
+
/// Removes all the GVs that aren't inside the desired Chunks.
-static void extractGVsFromModule(Oracle &O, Module &Program) {
+static void extractGVsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
// Get GVs inside desired chunks
- std::vector<GlobalVariable *> InitGVsToKeep;
- for (auto &GV : Program.globals())
- if (O.shouldKeep())
+ std::vector<Constant *> InitGVsToKeep;
+ for (auto &GV : Program.globals()) {
+ if (shouldAlwaysKeep(GV) || O.shouldKeep())
InitGVsToKeep.push_back(&GV);
+ }
// We create a vector first, then convert it to a set, so that we don't have
// to pay the cost of rebalancing the set frequently if the order we insert
// the elements doesn't match the order they should appear inside the set.
- std::set<GlobalVariable *> GVsToKeep(InitGVsToKeep.begin(),
- InitGVsToKeep.end());
+ DenseSet<Constant *> GVsToKeep(InitGVsToKeep.begin(), InitGVsToKeep.end());
// Delete out-of-chunk GVs and their uses
- std::vector<GlobalVariable *> ToRemove;
- std::vector<WeakVH> InstToRemove;
- for (auto &GV : Program.globals())
- if (!GVsToKeep.count(&GV)) {
- for (auto *U : GV.users())
- if (auto *Inst = dyn_cast<Instruction>(U))
- InstToRemove.push_back(Inst);
-
- GV.replaceAllUsesWith(getDefaultValue(GV.getType()));
- ToRemove.push_back(&GV);
- }
-
- // Delete (unique) Instruction uses of unwanted GVs
- for (Value *V : InstToRemove) {
- if (!V)
- continue;
- auto *Inst = cast<Instruction>(V);
- Inst->replaceAllUsesWith(getDefaultValue(Inst->getType()));
- Inst->eraseFromParent();
+ DenseSet<Constant *> ToRemove;
+ for (auto &GV : Program.globals()) {
+ if (!GVsToKeep.count(&GV))
+ ToRemove.insert(&GV);
}
- for (auto *GV : ToRemove)
- GV->eraseFromParent();
+ removeFromUsedLists(Program,
+ [&ToRemove](Constant *C) { return ToRemove.count(C); });
+
+ for (auto *GV : ToRemove) {
+ GV->replaceAllUsesWith(getDefaultValue(GV->getType()));
+ cast<GlobalVariable>(GV)->eraseFromParent();
+ }
}
void llvm::reduceGlobalsDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing GVs...\n";
- runDeltaPass(Test, extractGVsFromModule);
+ runDeltaPass(Test, extractGVsFromModule, "Reducing GlobalVariables");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.h
index fe7813c..1198dce 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.h
@@ -1,4 +1,4 @@
-//===- ReduceGlobalVars.h - Specialized Delta Pass ------------------------===//
+//===- ReduceGlobalVars.h - Specialized Delta Pass --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceIRReferences.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceIRReferences.cpp
index 975bdc2..fe4e13b 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceIRReferences.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceIRReferences.cpp
@@ -15,6 +15,8 @@
#include "ReduceIRReferences.h"
#include "Delta.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
using namespace llvm;
@@ -67,16 +69,15 @@
}
void llvm::reduceIRInstructionReferencesDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing IR references from instructions...\n";
- runDeltaPass(Test, stripIRFromInstructions);
+ runDeltaPass(Test, stripIRFromInstructions,
+ "Reducing IR references from instructions");
}
void llvm::reduceIRBlockReferencesDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing IR references from blocks...\n";
- runDeltaPass(Test, stripIRFromBlocks);
+ runDeltaPass(Test, stripIRFromBlocks, "Reducing IR references from blocks");
}
void llvm::reduceIRFunctionReferencesDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing IR references from functions...\n";
- runDeltaPass(Test, stripIRFromFunctions);
+ runDeltaPass(Test, stripIRFromFunctions,
+ "Reducing IR references from functions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp
new file mode 100644
index 0000000..c73e74e
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp
@@ -0,0 +1,68 @@
+//===- ReduceInstructionFlags.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to remove optimization flags on instructions
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceInstructionFlags.h"
+#include "Delta.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Operator.h"
+
+using namespace llvm;
+
+static void reduceFlagsInModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ for (Function &F : WorkItem.getModule()) {
+ for (Instruction &I : instructions(F)) {
+ if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I)) {
+ if (OBO->hasNoSignedWrap() && !O.shouldKeep())
+ I.setHasNoSignedWrap(false);
+ if (OBO->hasNoUnsignedWrap() && !O.shouldKeep())
+ I.setHasNoUnsignedWrap(false);
+ } else if (auto *PE = dyn_cast<PossiblyExactOperator>(&I)) {
+ if (PE->isExact() && !O.shouldKeep())
+ I.setIsExact(false);
+ } else if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
+ if (GEP->isInBounds() && !O.shouldKeep())
+ GEP->setIsInBounds(false);
+ } else if (auto *FPOp = dyn_cast<FPMathOperator>(&I)) {
+ FastMathFlags Flags = FPOp->getFastMathFlags();
+
+ if (Flags.allowReassoc() && !O.shouldKeep())
+ Flags.setAllowReassoc(false);
+
+ if (Flags.noNaNs() && !O.shouldKeep())
+ Flags.setNoNaNs(false);
+
+ if (Flags.noInfs() && !O.shouldKeep())
+ Flags.setNoInfs(false);
+
+ if (Flags.noSignedZeros() && !O.shouldKeep())
+ Flags.setNoSignedZeros(false);
+
+ if (Flags.allowReciprocal() && !O.shouldKeep())
+ Flags.setAllowReciprocal(false);
+
+ if (Flags.allowContract() && !O.shouldKeep())
+ Flags.setAllowContract(false);
+
+ if (Flags.approxFunc() && !O.shouldKeep())
+ Flags.setApproxFunc(false);
+
+ I.copyFastMathFlags(Flags);
+ }
+ }
+ }
+}
+
+void llvm::reduceInstructionFlagsDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceFlagsInModule, "Reducing Instruction Flags");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.h
new file mode 100644
index 0000000..1764c01
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.h
@@ -0,0 +1,18 @@
+//===- ReduceInstructionFlags.h - Specialized Delta Pass --------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINSTRUCTIONFLAGS_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINSTRUCTIONFLAGS_H
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceInstructionFlagsDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.cpp
index 4c3b4d3..f2895b3 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.cpp
@@ -13,6 +13,7 @@
#include "ReduceInstructionFlagsMIR.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
using namespace llvm;
static void removeFlagsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
@@ -30,6 +31,5 @@
}
void llvm::reduceInstructionFlagsMIRDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Instruction flags...\n";
- runDeltaPass(Test, removeFlagsFromModule);
+ runDeltaPass(Test, removeFlagsFromModule, "Reducing Instruction Flags");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.h
index a211994..a5a34d2 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionFlagsMIR.h
@@ -1,4 +1,4 @@
-//===- ReduceInstructionFlagsMIR.h - Specialized Delta Pass --------------===//
+//===- ReduceInstructionFlagsMIR.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.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp
index 078da9e..7dfe028 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp
@@ -17,9 +17,19 @@
using namespace llvm;
+/// Filter out cases where deleting the instruction will likely cause the
+/// user/def of the instruction to fail the verifier.
+//
+// TODO: Technically the verifier only enforces preallocated token usage and
+// there is a none token.
+static bool shouldAlwaysKeep(const Instruction &I) {
+ return I.isEHPad() || I.getType()->isTokenTy() || I.isSwiftError();
+}
+
/// Removes out-of-chunk arguments from functions, and modifies their calls
/// accordingly. It also removes allocations of out-of-chunk arguments.
-static void extractInstrFromModule(Oracle &O, Module &Program) {
+static void extractInstrFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
std::vector<Instruction *> InitInstToKeep;
for (auto &F : Program)
@@ -27,9 +37,10 @@
// Removing the terminator would make the block invalid. Only iterate over
// instructions before the terminator.
InitInstToKeep.push_back(BB.getTerminator());
- for (auto &Inst : make_range(BB.begin(), std::prev(BB.end())))
- if (O.shouldKeep())
+ for (auto &Inst : make_range(BB.begin(), std::prev(BB.end()))) {
+ if (shouldAlwaysKeep(Inst) || O.shouldKeep())
InitInstToKeep.push_back(&Inst);
+ }
}
// We create a vector first, then convert it to a set, so that we don't have
@@ -52,6 +63,5 @@
}
void llvm::reduceInstructionsDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Instructions...\n";
- runDeltaPass(Test, extractInstrFromModule);
+ runDeltaPass(Test, extractInstrFromModule, "Reducing Instructions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.h
index be568f1..8c13a02 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructions.h
@@ -1,4 +1,4 @@
-//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
+//===- ReduceInstructions.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.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp
index c87d5eb..b97d75a 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp
@@ -18,6 +18,7 @@
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
@@ -33,10 +34,10 @@
auto &MI = *RI;
// All Def operands explicit and implicit.
for (auto &MO : MI.operands()) {
- if (!MO.isReg() || !MO.isDef())
+ if (!MO.isReg() || !MO.isDef() || MO.isDead())
continue;
auto Reg = MO.getReg();
- if (Register::isPhysicalRegister(Reg))
+ if (Reg.isPhysical())
continue;
if (MRI->getRegClassOrRegBank(Reg) == RC && MRI->getType(Reg) == Ty &&
@@ -89,10 +90,10 @@
// some other dominating definition (that is not to be deleted).
for (auto *MI : ToDelete) {
for (auto &MO : MI->operands()) {
- if (!MO.isReg() || !MO.isDef())
+ if (!MO.isReg() || !MO.isDef() || MO.isDead())
continue;
auto Reg = MO.getReg();
- if (Register::isPhysicalRegister(Reg))
+ if (Reg.isPhysical())
continue;
auto UI = MRI->use_begin(Reg);
auto UE = MRI->use_end();
@@ -128,8 +129,13 @@
bool IsGeneric = MRI->getRegClassOrNull(Reg) == nullptr;
unsigned ImpDef = IsGeneric ? TargetOpcode::G_IMPLICIT_DEF
: TargetOpcode::IMPLICIT_DEF;
+
+ unsigned State = getRegState(MO);
+ if (MO.getSubReg())
+ State |= RegState::Undef;
+
BuildMI(*EntryMBB, EntryInsPt, DebugLoc(), TII->get(ImpDef))
- .addReg(NewReg, getRegState(MO), MO.getSubReg());
+ .addReg(NewReg, State, MO.getSubReg());
}
// Update all uses.
@@ -153,6 +159,5 @@
}
void llvm::reduceInstructionsMIRDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Instructions...\n";
- runDeltaPass(Test, extractInstrFromModule);
+ runDeltaPass(Test, extractInstrFromModule, "Reducing Instructions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h
index a59f1aa..70e0ac5 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h
@@ -1,4 +1,4 @@
-//===- ReduceInstructionsMIR.h - Specialized Delta Pass ------------------===//
+//===- ReduceInstructionsMIR.h - Specialized Delta Pass --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInvokes.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInvokes.cpp
new file mode 100644
index 0000000..c6425a7
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInvokes.cpp
@@ -0,0 +1,41 @@
+//===- ReduceInvokes.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to replace invokes with calls.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceInvokes.h"
+#include "Delta.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Transforms/Utils/Local.h"
+
+using namespace llvm;
+
+static void reduceInvokesInFunction(Oracle &O, Function &F) {
+ for (BasicBlock &BB : F) {
+ InvokeInst *Invoke = dyn_cast<InvokeInst>(BB.getTerminator());
+ if (Invoke && !O.shouldKeep())
+ changeToCall(Invoke);
+ }
+
+ // TODO: We most likely are leaving behind dead landingpad blocks. Should we
+ // delete unreachable blocks now, or leave that for the unreachable block
+ // reduction.
+}
+
+static void reduceInvokesInModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ for (Function &F : WorkItem.getModule()) {
+ if (F.hasPersonalityFn())
+ reduceInvokesInFunction(O, F);
+ }
+}
+
+void llvm::reduceInvokesDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceInvokesInModule, "Reducing Invokes");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInvokes.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInvokes.h
new file mode 100644
index 0000000..9607add
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceInvokes.h
@@ -0,0 +1,18 @@
+//===- ReduceInvokes.h - Specialized Delta Pass -----------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINVOKES_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINVOKES_H
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceInvokesDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMemoryOperations.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMemoryOperations.cpp
new file mode 100644
index 0000000..8e73ea0
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMemoryOperations.cpp
@@ -0,0 +1,110 @@
+//===- ReduceOpcodes.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceMemoryOperations.h"
+#include "Delta.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+
+using namespace llvm;
+
+static void removeVolatileInFunction(Oracle &O, Function &F) {
+ LLVMContext &Ctx = F.getContext();
+ for (Instruction &I : instructions(F)) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
+ if (LI->isVolatile() && !O.shouldKeep())
+ LI->setVolatile(false);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
+ if (SI->isVolatile() && !O.shouldKeep())
+ SI->setVolatile(false);
+ } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(&I)) {
+ if (RMW->isVolatile() && !O.shouldKeep())
+ RMW->setVolatile(false);
+ } else if (AtomicCmpXchgInst *CmpXChg = dyn_cast<AtomicCmpXchgInst>(&I)) {
+ if (CmpXChg->isVolatile() && !O.shouldKeep())
+ CmpXChg->setVolatile(false);
+ } else if (MemIntrinsic *MemIntrin = dyn_cast<MemIntrinsic>(&I)) {
+ if (MemIntrin->isVolatile() && !O.shouldKeep())
+ MemIntrin->setVolatile(ConstantInt::getFalse(Ctx));
+ }
+ }
+}
+
+static void removeVolatileInModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ for (Function &F : WorkItem.getModule())
+ removeVolatileInFunction(O, F);
+}
+
+void llvm::reduceVolatileInstructionsDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, removeVolatileInModule, "Reducing Volatile Instructions");
+}
+
+static void reduceAtomicSyncScopesInFunction(Oracle &O, Function &F) {
+ for (Instruction &I : instructions(F)) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
+ if (LI->getSyncScopeID() != SyncScope::System && !O.shouldKeep())
+ LI->setSyncScopeID(SyncScope::System);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
+ if (SI->getSyncScopeID() != SyncScope::System && !O.shouldKeep())
+ SI->setSyncScopeID(SyncScope::System);
+ } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(&I)) {
+ if (RMW->getSyncScopeID() != SyncScope::System && !O.shouldKeep())
+ RMW->setSyncScopeID(SyncScope::System);
+ } else if (AtomicCmpXchgInst *CmpXChg = dyn_cast<AtomicCmpXchgInst>(&I)) {
+ if (CmpXChg->getSyncScopeID() != SyncScope::System && !O.shouldKeep())
+ CmpXChg->setSyncScopeID(SyncScope::System);
+ } else if (FenceInst *Fence = dyn_cast<FenceInst>(&I)) {
+ if (Fence->getSyncScopeID() != SyncScope::System && !O.shouldKeep())
+ Fence->setSyncScopeID(SyncScope::System);
+ }
+ }
+}
+
+static void reduceAtomicSyncScopesInModule(Oracle &O,
+ ReducerWorkItem &WorkItem) {
+ for (Function &F : WorkItem.getModule())
+ reduceAtomicSyncScopesInFunction(O, F);
+}
+
+void llvm::reduceAtomicSyncScopesDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceAtomicSyncScopesInModule,
+ "Reducing Atomic Sync Scopes");
+}
+
+// TODO: Might be helpful to incrementally relax orders
+static void reduceAtomicOrderingInFunction(Oracle &O, Function &F) {
+ for (Instruction &I : instructions(F)) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
+ if (LI->getOrdering() != AtomicOrdering::NotAtomic && !O.shouldKeep())
+ LI->setAtomic(AtomicOrdering::NotAtomic);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
+ if (SI->getOrdering() != AtomicOrdering::NotAtomic && !O.shouldKeep())
+ SI->setAtomic(AtomicOrdering::NotAtomic);
+ } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(&I)) {
+ if (RMW->getOrdering() != AtomicOrdering::Monotonic && !O.shouldKeep())
+ RMW->setOrdering(AtomicOrdering::Monotonic);
+ } else if (AtomicCmpXchgInst *CmpXChg = dyn_cast<AtomicCmpXchgInst>(&I)) {
+ if (CmpXChg->getSuccessOrdering() != AtomicOrdering::Monotonic &&
+ !O.shouldKeep())
+ CmpXChg->setSuccessOrdering(AtomicOrdering::Monotonic);
+ if (CmpXChg->getFailureOrdering() != AtomicOrdering::Monotonic &&
+ !O.shouldKeep())
+ CmpXChg->setFailureOrdering(AtomicOrdering::Monotonic);
+ }
+ }
+}
+
+static void reduceAtomicOrderingInModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ for (Function &F : WorkItem.getModule())
+ reduceAtomicOrderingInFunction(O, F);
+}
+
+void llvm::reduceAtomicOrderingDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceAtomicOrderingInModule, "Reducing Atomic Ordering");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMemoryOperations.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMemoryOperations.h
new file mode 100644
index 0000000..ca6a770
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMemoryOperations.h
@@ -0,0 +1,20 @@
+//===- ReduceMemoryOperations.h - Specialized Delta Pass --------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEMEMORYOPERATIONS_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEMEMORYOPERATIONS_H
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceVolatileInstructionsDeltaPass(TestRunner &Test);
+void reduceAtomicSyncScopesDeltaPass(TestRunner &Test);
+void reduceAtomicOrderingDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
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 078230e..d491858 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
@@ -16,17 +16,66 @@
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IntrinsicInst.h"
#include <vector>
using namespace llvm;
+static bool shouldKeepDebugIntrinsicMetadata(Instruction &I, MDNode &MD) {
+ return isa<DILocation>(MD) && isa<DbgInfoIntrinsic>(I);
+}
+
+static bool shouldKeepDebugNamedMetadata(NamedMDNode &MD) {
+ return MD.getName() == "llvm.dbg.cu" && MD.getNumOperands() != 0;
+}
+
+// Named metadata with simple list-like behavior, so that it's valid to remove
+// operands individually.
+static constexpr StringLiteral ListNamedMetadata[] = {
+ "llvm.module.flags",
+ "llvm.ident",
+ "opencl.spir.version",
+ "opencl.ocl.version",
+ "opencl.used.extensions",
+ "opencl.used.optional.core.features",
+ "opencl.compiler.options"
+};
+
+/// Remove unneeded arguments to named metadata.
+static void reduceNamedMetadataOperands(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &M = WorkItem.getModule();
+
+ for (StringRef MDName : ListNamedMetadata) {
+ NamedMDNode *NamedNode = M.getNamedMetadata(MDName);
+ if (!NamedNode)
+ continue;
+
+ bool MadeChange = false;
+ SmallVector<MDNode *, 16> KeptOperands;
+ for (auto I : seq<unsigned>(0, NamedNode->getNumOperands())) {
+ if (O.shouldKeep())
+ KeptOperands.push_back(NamedNode->getOperand(I));
+ else
+ MadeChange = true;
+ }
+
+ if (MadeChange) {
+ NamedNode->clearOperands();
+ for (MDNode *KeptOperand : KeptOperands)
+ NamedNode->addOperand(KeptOperand);
+ }
+ }
+}
+
/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug
/// functions that aren't inside the desired Chunks.
-static void extractMetadataFromModule(Oracle &O, Module &Program) {
+static void extractMetadataFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
// Get out-of-chunk Named metadata nodes
SmallVector<NamedMDNode *> NamedNodesToDelete;
for (NamedMDNode &MD : Program.named_metadata())
- if (!O.shouldKeep())
+ if (!shouldKeepDebugNamedMetadata(MD) && !O.shouldKeep())
NamedNodesToDelete.push_back(&MD);
for (NamedMDNode *NN : NamedNodesToDelete) {
@@ -58,15 +107,18 @@
for (Instruction &I : instructions(F)) {
SmallVector<std::pair<unsigned, MDNode *>> MDs;
I.getAllMetadata(MDs);
- for (std::pair<unsigned, MDNode *> &MD : MDs)
- if (!O.shouldKeep())
+ for (std::pair<unsigned, MDNode *> &MD : MDs) {
+ if (!shouldKeepDebugIntrinsicMetadata(I, *MD.second) && !O.shouldKeep())
I.setMetadata(MD.first, nullptr);
+ }
}
}
}
void llvm::reduceMetadataDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Metadata...\n";
- runDeltaPass(Test, extractMetadataFromModule);
- outs() << "----------------------------\n";
+ runDeltaPass(Test, extractMetadataFromModule, "Reducing Metadata");
+}
+
+void llvm::reduceNamedMetadataDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceNamedMetadataOperands, "Reducing Named Metadata");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.h
index 6efc3f5..f3af31a 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceMetadata.h
@@ -1,4 +1,4 @@
-//===- ReduceMetadata.h - Specialized Delta Pass --------------------------===//
+//===- ReduceMetadata.h - Specialized Delta Pass ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -18,6 +18,7 @@
namespace llvm {
void reduceMetadataDeltaPass(TestRunner &Test);
+void reduceNamedMetadataDeltaPass(TestRunner &Test);
} // namespace llvm
#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp
index cbde789..17930ab 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp
@@ -14,7 +14,9 @@
using namespace llvm;
-static void clearModuleData(Oracle &O, Module &Program) {
+static void clearModuleData(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
if (!Program.getModuleIdentifier().empty() && !O.shouldKeep())
Program.setModuleIdentifier("");
if (!Program.getSourceFileName().empty() && !O.shouldKeep())
@@ -25,6 +27,5 @@
}
void llvm::reduceModuleDataDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing Module Data...\n";
- runDeltaPass(Test, clearModuleData);
+ runDeltaPass(Test, clearModuleData, "Reducing Module Data");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.h
index 972c534..960fe8c 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceModuleData.h
@@ -1,4 +1,4 @@
-//===- ReduceModuleData.h --------------------------------------------===//
+//===- ReduceModuleData.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.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp
new file mode 100644
index 0000000..2140544
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp
@@ -0,0 +1,282 @@
+//===- ReduceOpcodes.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to replace instructions that are likely to codegen to simpler or smaller
+// sequences. This is a fuzzy and target specific concept.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceOpcodes.h"
+#include "Delta.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicsAMDGPU.h"
+
+using namespace llvm;
+
+// Assume outgoing undef arguments aren't relevant.
+// TODO: Maybe skip any trivial constant arguments.
+static bool shouldIgnoreArgument(const Value *V) {
+ return isa<UndefValue>(V);
+}
+
+static Value *replaceIntrinsic(Module &M, IntrinsicInst *II,
+ Intrinsic::ID NewIID,
+ ArrayRef<Type *> Tys = std::nullopt) {
+ Function *NewFunc = Intrinsic::getDeclaration(&M, NewIID, Tys);
+ II->setCalledFunction(NewFunc);
+ return II;
+}
+
+static Value *reduceIntrinsic(Oracle &O, Module &M, IntrinsicInst *II) {
+ IRBuilder<> B(II);
+ switch (II->getIntrinsicID()) {
+ case Intrinsic::sqrt:
+ if (O.shouldKeep())
+ return nullptr;
+
+ return B.CreateFMul(II->getArgOperand(0),
+ ConstantFP::get(II->getType(), 2.0));
+ case Intrinsic::minnum:
+ case Intrinsic::maxnum:
+ case Intrinsic::minimum:
+ case Intrinsic::maximum:
+ case Intrinsic::amdgcn_fmul_legacy:
+ if (O.shouldKeep())
+ return nullptr;
+ return B.CreateFMul(II->getArgOperand(0), II->getArgOperand(1));
+ case Intrinsic::amdgcn_workitem_id_y:
+ case Intrinsic::amdgcn_workitem_id_z:
+ if (O.shouldKeep())
+ return nullptr;
+ return replaceIntrinsic(M, II, Intrinsic::amdgcn_workitem_id_x);
+ case Intrinsic::amdgcn_workgroup_id_y:
+ case Intrinsic::amdgcn_workgroup_id_z:
+ if (O.shouldKeep())
+ return nullptr;
+ return replaceIntrinsic(M, II, Intrinsic::amdgcn_workgroup_id_x);
+ case Intrinsic::amdgcn_div_fixup:
+ case Intrinsic::amdgcn_fma_legacy:
+ if (O.shouldKeep())
+ return nullptr;
+ return replaceIntrinsic(M, II, Intrinsic::fma, {II->getType()});
+ default:
+ return nullptr;
+ }
+}
+
+/// Look for calls that look like they could be replaced with a load or store.
+static bool callLooksLikeLoadStore(CallBase *CB, Value *&DataArg,
+ Value *&PtrArg) {
+ const bool IsStore = CB->getType()->isVoidTy();
+
+ PtrArg = nullptr;
+ DataArg = nullptr;
+ for (Value *Arg : CB->args()) {
+ if (shouldIgnoreArgument(Arg))
+ continue;
+
+ if (!Arg->getType()->isSized())
+ return false;
+
+ PointerType *PT = dyn_cast<PointerType>(Arg->getType());
+ if (!PtrArg && PT) {
+ // FIXME: Could create bitcast for typed pointers, but roll back unused
+ // replacement only erases one instruction.
+ if (!IsStore && !PT->isOpaqueOrPointeeTypeMatches(CB->getType()))
+ return false;
+
+ PtrArg = Arg;
+ continue;
+ }
+
+ if (!IsStore || DataArg)
+ return false;
+
+ DataArg = Arg;
+ }
+
+ if (IsStore && !DataArg) {
+ // FIXME: For typed pointers, use element type?
+ DataArg = ConstantInt::get(IntegerType::getInt32Ty(CB->getContext()), 0);
+ }
+
+ // If we didn't find any arguments, we can fill in the pointer.
+ if (!PtrArg) {
+ unsigned AS = CB->getModule()->getDataLayout().getAllocaAddrSpace();
+
+ PointerType *PtrTy =
+ PointerType::get(DataArg ? DataArg->getType()
+ : IntegerType::getInt32Ty(CB->getContext()),
+ AS);
+
+ 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;
+}
+
+// TODO: Replace 2 pointer argument calls with memcpy
+static Value *tryReplaceCallWithLoadStore(Oracle &O, Module &M, CallBase *CB) {
+ Value *PtrArg = nullptr;
+ Value *DataArg = nullptr;
+ if (!callLooksLikeLoadStore(CB, DataArg, PtrArg) || O.shouldKeep())
+ return nullptr;
+
+ IRBuilder<> B(CB);
+ if (DataArg)
+ return B.CreateStore(DataArg, PtrArg, true);
+ return B.CreateLoad(CB->getType(), PtrArg, true);
+}
+
+static bool callLooksLikeOperator(CallBase *CB,
+ SmallVectorImpl<Value *> &OperatorArgs) {
+ Type *ReturnTy = CB->getType();
+ if (!ReturnTy->isFirstClassType())
+ return false;
+
+ for (Value *Arg : CB->args()) {
+ if (shouldIgnoreArgument(Arg))
+ continue;
+
+ if (Arg->getType() != ReturnTy)
+ return false;
+
+ OperatorArgs.push_back(Arg);
+ }
+
+ return true;
+}
+
+static Value *tryReplaceCallWithOperator(Oracle &O, Module &M, CallBase *CB) {
+ SmallVector<Value *, 4> Arguments;
+
+ if (!callLooksLikeOperator(CB, Arguments) || Arguments.size() > 3)
+ return nullptr;
+
+ if (O.shouldKeep())
+ return nullptr;
+
+ IRBuilder<> B(CB);
+ if (CB->getType()->isFPOrFPVectorTy()) {
+ switch (Arguments.size()) {
+ case 1:
+ return B.CreateFNeg(Arguments[0]);
+ case 2:
+ return B.CreateFMul(Arguments[0], Arguments[1]);
+ case 3:
+ return B.CreateIntrinsic(Intrinsic::fma, {CB->getType()}, Arguments);
+ default:
+ return nullptr;
+ }
+
+ llvm_unreachable("all argument sizes handled");
+ }
+
+ if (CB->getType()->isIntOrIntVectorTy()) {
+ switch (Arguments.size()) {
+ case 1:
+ return B.CreateUnaryIntrinsic(Intrinsic::bswap, Arguments[0]);
+ case 2:
+ return B.CreateAnd(Arguments[0], Arguments[1]);
+ case 3:
+ return B.CreateIntrinsic(Intrinsic::fshl, {CB->getType()}, Arguments);
+ default:
+ return nullptr;
+ }
+
+ llvm_unreachable("all argument sizes handled");
+ }
+
+ return nullptr;
+}
+
+static Value *reduceInstruction(Oracle &O, Module &M, Instruction &I) {
+ IRBuilder<> B(&I);
+
+ // TODO: fp binary operator with constant to fneg
+ switch (I.getOpcode()) {
+ case Instruction::FDiv:
+ case Instruction::FRem:
+ if (O.shouldKeep())
+ return nullptr;
+
+ // Divisions tends to codegen into a long sequence or a library call.
+ return B.CreateFMul(I.getOperand(0), I.getOperand(1));
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ if (O.shouldKeep())
+ return nullptr;
+
+ // Divisions tends to codegen into a long sequence or a library call.
+ return B.CreateMul(I.getOperand(0), I.getOperand(1));
+ case Instruction::Add:
+ case Instruction::Sub: {
+ if (O.shouldKeep())
+ return nullptr;
+
+ // Add/sub are more likely codegen to instructions with carry out side
+ // effects.
+ return B.CreateOr(I.getOperand(0), I.getOperand(1));
+ }
+ case Instruction::Call: {
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
+ return reduceIntrinsic(O, M, II);
+
+ CallBase *CB = cast<CallBase>(&I);
+
+ if (Value *NewOp = tryReplaceCallWithOperator(O, M, CB))
+ return NewOp;
+
+ if (Value *NewOp = tryReplaceCallWithLoadStore(O, M, CB))
+ return NewOp;
+
+ return nullptr;
+ }
+ default:
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+static void replaceOpcodesInModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Mod = WorkItem.getModule();
+
+ for (Function &F : Mod) {
+ for (BasicBlock &BB : F)
+ for (Instruction &I : make_early_inc_range(BB)) {
+ Instruction *Replacement =
+ dyn_cast_or_null<Instruction>(reduceInstruction(O, Mod, I));
+ if (Replacement && Replacement != &I) {
+ if (isa<FPMathOperator>(Replacement))
+ Replacement->copyFastMathFlags(&I);
+
+ Replacement->copyIRFlags(&I);
+ Replacement->copyMetadata(I);
+ Replacement->takeName(&I);
+ I.replaceAllUsesWith(Replacement);
+ I.eraseFromParent();
+ }
+ }
+ }
+}
+
+void llvm::reduceOpcodesDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, replaceOpcodesInModule, "Reducing Opcodes");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.h
new file mode 100644
index 0000000..79edc7f
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.h
@@ -0,0 +1,18 @@
+//===- ReduceOpcodes.h - Specialized Delta Pass -----------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEOPCODES_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEOPCODES_H
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceOpcodesDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
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 c28bbb2..6f9cafb 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp
@@ -95,7 +95,9 @@
}
/// Removes out-of-chunk operand bundles from calls.
-static void extractOperandBundesFromModule(Oracle &O, Module &Program) {
+static void extractOperandBundesFromModule(Oracle &O,
+ ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
OperandBundleRemapper R(O);
R.visit(Program);
@@ -104,6 +106,6 @@
}
void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing OperandBundes...\n";
- runDeltaPass(Test, extractOperandBundesFromModule);
+ runDeltaPass(Test, extractOperandBundesFromModule,
+ "Reducing Operand Bundles");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h
index d07e021..390b029 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h
@@ -1,4 +1,4 @@
-//===- ReduceOperandBundes.h - Specialized Delta Pass ---------------------===//
+//===- ReduceOperandBundes.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.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp
index 7c144eb..6bf84f2 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp
@@ -18,13 +18,26 @@
using namespace PatternMatch;
static void
-extractOperandsFromModule(Oracle &O, Module &Program,
+extractOperandsFromModule(Oracle &O, ReducerWorkItem &WorkItem,
function_ref<Value *(Use &)> ReduceValue) {
+ Module &Program = WorkItem.getModule();
+
for (auto &F : Program.functions()) {
for (auto &I : instructions(&F)) {
+ if (PHINode *Phi = dyn_cast<PHINode>(&I)) {
+ for (auto &Op : Phi->incoming_values()) {
+ if (!O.shouldKeep()) {
+ if (Value *Reduced = ReduceValue(Op))
+ Phi->setIncomingValueForBlock(Phi->getIncomingBlock(Op), Reduced);
+ }
+ }
+
+ continue;
+ }
+
for (auto &Op : I.operands()) {
- if (!O.shouldKeep()) {
- if (Value *Reduced = ReduceValue(Op))
+ if (Value *Reduced = ReduceValue(Op)) {
+ if (!O.shouldKeep())
Op.set(Reduced);
}
}
@@ -63,14 +76,23 @@
return true;
}
+static bool switchCaseExists(Use &Op, ConstantInt *CI) {
+ SwitchInst *SI = dyn_cast<SwitchInst>(Op.getUser());
+ if (!SI)
+ return false;
+ return SI->findCaseValue(CI) != SI->case_default();
+}
+
void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Operands to one...\n";
auto ReduceValue = [](Use &Op) -> Value * {
if (!shouldReduceOperand(Op))
return nullptr;
Type *Ty = Op->getType();
if (auto *IntTy = dyn_cast<IntegerType>(Ty)) {
+ // Don't duplicate an existing switch case.
+ if (switchCaseExists(Op, ConstantInt::get(IntTy, 1)))
+ return nullptr;
// Don't replace existing ones and zeroes.
return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(IntTy, 1);
}
@@ -82,36 +104,48 @@
if (isOne(Op) || isZero(Op) || isZeroOrOneFP(Op))
return nullptr;
- if (auto *IntTy = dyn_cast<IntegerType>(VT->getElementType()))
- return ConstantVector::getSplat(VT->getElementCount(),
- ConstantInt::get(IntTy, 1));
-
- return ConstantVector::getSplat(
- VT->getElementCount(), ConstantFP::get(VT->getElementType(), 1.0));
+ Type *ElementType = VT->getElementType();
+ Constant *C;
+ if (ElementType->isFloatingPointTy()) {
+ C = ConstantFP::get(ElementType, 1.0);
+ } else if (IntegerType *IntTy = dyn_cast<IntegerType>(ElementType)) {
+ C = ConstantInt::get(IntTy, 1);
+ } else {
+ return nullptr;
+ }
+ return ConstantVector::getSplat(VT->getElementCount(), C);
}
return nullptr;
};
- runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
- extractOperandsFromModule(O, Program, ReduceValue);
- });
+ runDeltaPass(
+ Test,
+ [ReduceValue](Oracle &O, ReducerWorkItem &WorkItem) {
+ extractOperandsFromModule(O, WorkItem, ReduceValue);
+ },
+ "Reducing Operands to one");
}
void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Operands to zero...\n";
auto ReduceValue = [](Use &Op) -> Value * {
if (!shouldReduceOperand(Op))
return nullptr;
+ // Don't duplicate an existing switch case.
+ if (auto *IntTy = dyn_cast<IntegerType>(Op->getType()))
+ if (switchCaseExists(Op, ConstantInt::get(IntTy, 0)))
+ return nullptr;
// Don't replace existing zeroes.
return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType());
};
- runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
- extractOperandsFromModule(O, Program, ReduceValue);
- });
+ runDeltaPass(
+ Test,
+ [ReduceValue](Oracle &O, ReducerWorkItem &Program) {
+ extractOperandsFromModule(O, Program, ReduceValue);
+ },
+ "Reducing Operands to zero");
}
void llvm::reduceOperandsNaNDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Operands to NaN...\n";
auto ReduceValue = [](Use &Op) -> Value * {
Type *Ty = Op->getType();
if (!Ty->isFPOrFPVectorTy())
@@ -131,7 +165,10 @@
return ConstantFP::getQNaN(Ty);
};
- runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
- extractOperandsFromModule(O, Program, ReduceValue);
- });
+ runDeltaPass(
+ Test,
+ [ReduceValue](Oracle &O, ReducerWorkItem &Program) {
+ extractOperandsFromModule(O, Program, ReduceValue);
+ },
+ "Reducing Operands to NaN");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.h
index 034f49b..b4a1899 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperands.h
@@ -1,4 +1,4 @@
-//===----------------------------------------------------------------------===//
+//===------------------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
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 2dd113e..a634c3a 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.cpp
@@ -187,7 +187,9 @@
}
}
-static void extractOperandsFromModule(Oracle &O, Module &Program) {
+static void extractOperandsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
for (Function &F : Program.functions()) {
SmallVector<std::pair<Use *, Value *>> Replacements;
opportunities(F, [&](Use &Op, ArrayRef<Value *> Candidates) {
@@ -212,12 +214,16 @@
}
});
- for (std::pair<Use *, Value *> P : Replacements)
- P.first->set(P.second);
+ for (std::pair<Use *, Value *> P : Replacements) {
+ if (PHINode *Phi = dyn_cast<PHINode>(P.first->getUser()))
+ Phi->setIncomingValueForBlock(Phi->getIncomingBlock(*P.first), P.second);
+ else
+ P.first->set(P.second);
+ }
}
}
void llvm::reduceOperandsSkipDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing operands by skipping over instructions ...\n";
- runDeltaPass(Test, extractOperandsFromModule);
+ runDeltaPass(Test, extractOperandsFromModule,
+ "Reducing operands by skipping over instructions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.h
index 79ee462..7989701 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsSkip.h
@@ -1,4 +1,4 @@
-//===----------------------------------------------------------------------===//
+//===------------------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
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 f738a51..0f949ab 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp
@@ -173,7 +173,9 @@
NewF->setName(FName);
}
-static void reduceOperandsToArgs(Oracle &O, Module &Program) {
+static void reduceOperandsToArgs(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
SmallVector<Use *> OperandsToReduce;
for (Function &F : make_early_inc_range(Program.functions())) {
if (!canReplaceFunction(&F))
@@ -195,6 +197,6 @@
}
void llvm::reduceOperandsToArgsDeltaPass(TestRunner &Test) {
- outs() << "*** Converting operands to function arguments ...\n";
- return runDeltaPass(Test, reduceOperandsToArgs);
+ runDeltaPass(Test, reduceOperandsToArgs,
+ "Converting operands to function arguments");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.h
index 2bff393..23043dd 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.h
@@ -1,4 +1,4 @@
-//===----------------------------------------------------------------------===//
+//===------------------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterDefs.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterDefs.cpp
index ab4d28a..9725964 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterDefs.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterDefs.cpp
@@ -13,6 +13,7 @@
#include "ReduceRegisterDefs.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
@@ -39,8 +40,8 @@
int NumOperands = MI.getNumOperands();
int NumRequiredOps = MI.getNumExplicitOperands() +
- MI.getDesc().getNumImplicitDefs() +
- MI.getDesc().getNumImplicitUses();
+ MI.getDesc().implicit_defs().size() +
+ MI.getDesc().implicit_uses().size();
bool HaveDelete = false;
// Do an initial scan in case the instruction defines the same register
@@ -117,6 +118,5 @@
}
void llvm::reduceRegisterDefsMIRDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing register defs...\n";
- runDeltaPass(Test, removeDefsFromModule);
+ runDeltaPass(Test, removeDefsFromModule, "Reducing register defs");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.cpp
index 93d833c..f900d5c 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterMasks.cpp
@@ -13,6 +13,7 @@
#include "ReduceRegisterMasks.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
@@ -68,6 +69,5 @@
}
void llvm::reduceRegisterMasksMIRDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing register masks...\n";
- runDeltaPass(Test, reduceMasksInModule);
+ runDeltaPass(Test, reduceMasksInModule, "Reducing register masks");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterUses.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterUses.cpp
index a461cb8..a608935 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterUses.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceRegisterUses.cpp
@@ -13,6 +13,7 @@
#include "ReduceRegisterUses.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
@@ -28,8 +29,8 @@
int NumOperands = MI.getNumOperands();
int NumRequiredOps = MI.getNumExplicitOperands() +
- MI.getDesc().getNumImplicitDefs() +
- MI.getDesc().getNumImplicitUses();
+ MI.getDesc().implicit_defs().size() +
+ MI.getDesc().implicit_uses().size();
for (int I = NumOperands - 1; I >= 0; --I) {
MachineOperand &MO = MI.getOperand(I);
@@ -62,6 +63,5 @@
}
void llvm::reduceRegisterUsesMIRDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing register uses...\n";
- runDeltaPass(Test, removeUsesFromModule);
+ runDeltaPass(Test, removeUsesFromModule, "Reducing register uses");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp
index a86db31..5b124a4 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp
@@ -27,7 +27,10 @@
/// Removes all special globals aren't inside any of the
/// desired Chunks.
-static void extractSpecialGlobalsFromModule(Oracle &O, Module &Program) {
+static void extractSpecialGlobalsFromModule(Oracle &O,
+ ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+
for (StringRef Name : SpecialGlobalNames) {
if (auto *Used = Program.getNamedGlobal(Name)) {
Used->replaceAllUsesWith(getDefaultValue(Used->getType()));
@@ -37,7 +40,6 @@
}
void llvm::reduceSpecialGlobalsDeltaPass(TestRunner &Test) {
- errs() << "*** Reducing Special Globals ...\n";
- runDeltaPass(Test, extractSpecialGlobalsFromModule);
- errs() << "----------------------------\n";
+ runDeltaPass(Test, extractSpecialGlobalsFromModule,
+ "Reducing Special Globals");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h
index c0f3f9e..d177905 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.h
@@ -1,4 +1,4 @@
-//===- ReduceSpecialGlobals.h - Specialized Delta Pass --------------------===//
+//===- ReduceSpecialGlobals.h - Specialized Delta Pass ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
new file mode 100644
index 0000000..c49fcb9
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
@@ -0,0 +1,78 @@
+//===- ReduceUsingSimplifyCFG.h - 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 call SimplifyCFG on individual basic blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceUsingSimplifyCFG.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Transforms/Utils/Local.h"
+
+using namespace llvm;
+
+static void reduceUsingSimplifyCFG(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+ SmallVector<BasicBlock *, 16> ToSimplify;
+ for (auto &F : Program)
+ for (auto &BB : F)
+ if (!O.shouldKeep())
+ ToSimplify.push_back(&BB);
+ TargetTransformInfo TTI(Program.getDataLayout());
+ for (auto *BB : ToSimplify)
+ simplifyCFG(BB, TTI);
+}
+
+void llvm::reduceUsingSimplifyCFGDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceUsingSimplifyCFG, "Reducing using SimplifyCFG");
+}
+static void reduceConditionals(Oracle &O, ReducerWorkItem &WorkItem,
+ bool Direction) {
+ Module &M = WorkItem.getModule();
+ SmallVector<BasicBlock *, 16> ToSimplify;
+
+ for (auto &F : M) {
+ for (auto &BB : F) {
+ auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
+ if (!BR || !BR->isConditional() || O.shouldKeep())
+ continue;
+
+ if (Direction)
+ BR->setCondition(ConstantInt::getTrue(BR->getContext()));
+ else
+ BR->setCondition(ConstantInt::getFalse(BR->getContext()));
+
+ ToSimplify.push_back(&BB);
+ }
+ }
+
+ TargetTransformInfo TTI(M.getDataLayout());
+ for (auto *BB : ToSimplify)
+ simplifyCFG(BB, TTI);
+}
+
+void llvm::reduceConditionalsTrueDeltaPass(TestRunner &Test) {
+ runDeltaPass(
+ Test,
+ [](Oracle &O, ReducerWorkItem &WorkItem) {
+ reduceConditionals(O, WorkItem, true);
+ },
+ "Reducing conditional branches to true");
+}
+
+void llvm::reduceConditionalsFalseDeltaPass(TestRunner &Test) {
+ runDeltaPass(
+ Test,
+ [](Oracle &O, ReducerWorkItem &WorkItem) {
+ reduceConditionals(O, WorkItem, false);
+ },
+ "Reducing conditional branches to false");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h
new file mode 100644
index 0000000..01a1460
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h
@@ -0,0 +1,25 @@
+//===- ReduceUsingSimplifyCFG.h - Specialized Delta Pass --------*- 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 call SimplifyCFG on individual basic blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_SIMPLIFYCFG_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_SIMPLIFYCFG_H
+
+#include "Delta.h"
+
+namespace llvm {
+void reduceUsingSimplifyCFGDeltaPass(TestRunner &Test);
+void reduceConditionalsTrueDeltaPass(TestRunner &Test);
+void reduceConditionalsFalseDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceVirtualRegisters.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceVirtualRegisters.cpp
index 1c5bda8..eed5be7 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceVirtualRegisters.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/ReduceVirtualRegisters.cpp
@@ -13,6 +13,7 @@
#include "ReduceVirtualRegisters.h"
#include "Delta.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
@@ -41,6 +42,6 @@
}
void llvm::reduceVirtualRegisterHintsDeltaPass(TestRunner &Test) {
- outs() << "*** Reducing virtual register hints from functions...\n";
- runDeltaPass(Test, dropRegisterHintsFromFunctions);
+ runDeltaPass(Test, dropRegisterHintsFromFunctions,
+ "Reducing virtual register hints from functions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/RunIRPasses.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/RunIRPasses.cpp
new file mode 100644
index 0000000..acef29a
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/RunIRPasses.cpp
@@ -0,0 +1,54 @@
+//===- RunIRPasses.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "RunIRPasses.h"
+#include "Delta.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+extern cl::OptionCategory LLVMReduceOptions;
+
+static cl::opt<std::string> PassPipeline(
+ "ir-passes",
+ cl::desc("A textual description of the pass pipeline, same as "
+ "what's passed to `opt -passes`."),
+ cl::init("function(sroa,instcombine,gvn,simplifycfg,infer-address-spaces)"),
+ cl::cat(LLVMReduceOptions));
+
+static void runPasses(Oracle &O, ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ PassInstrumentationCallbacks PIC;
+ PIC.registerShouldRunOptionalPassCallback(
+ [&](StringRef, Any) { return !O.shouldKeep(); });
+ PassBuilder PB(nullptr, PipelineTuningOptions(), std::nullopt, &PIC);
+
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ ModulePassManager MPM;
+ if (auto Err = PB.parsePassPipeline(MPM, PassPipeline)) {
+ errs() << toString(std::move(Err)) << "\n";
+ report_fatal_error("Error constructing pass pipeline");
+ }
+ MPM.run(Program, MAM);
+}
+
+void llvm::runIRPassesDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, runPasses, "Running passes");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/RunIRPasses.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/RunIRPasses.h
new file mode 100644
index 0000000..f1d4140
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/RunIRPasses.h
@@ -0,0 +1,18 @@
+//===- RunIRPasses.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_RUNPASSES_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_RUNPASSES_H
+
+#include "Delta.h"
+
+namespace llvm {
+void runIRPassesDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/SimplifyInstructions.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/SimplifyInstructions.cpp
index 6e2e52a..fc21593 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/SimplifyInstructions.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/SimplifyInstructions.cpp
@@ -19,20 +19,21 @@
/// Calls simplifyInstruction in each instruction in functions, and replaces
/// their values.
-static void extractInstrFromModule(Oracle &O, Module &Program) {
+static void extractInstrFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
std::vector<Instruction *> InstsToDelete;
+ Module &Program = WorkItem.getModule();
const DataLayout &DL = Program.getDataLayout();
std::vector<Instruction *> InstToDelete;
for (auto &F : Program) {
for (auto &BB : F) {
for (auto &Inst : BB) {
- if (O.shouldKeep())
- continue;
SimplifyQuery Q(DL, &Inst);
if (Value *Simplified = simplifyInstruction(&Inst, Q)) {
+ if (O.shouldKeep())
+ continue;
Inst.replaceAllUsesWith(Simplified);
InstToDelete.push_back(&Inst);
}
@@ -45,6 +46,5 @@
}
void llvm::simplifyInstructionsDeltaPass(TestRunner &Test) {
- outs() << "*** Simplifying Instructions...\n";
- runDeltaPass(Test, extractInstrFromModule);
+ runDeltaPass(Test, extractInstrFromModule, "Simplifying Instructions");
}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp
new file mode 100644
index 0000000..a65e55d
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.cpp
@@ -0,0 +1,29 @@
+//===- StripDebugInfo.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "StripDebugInfo.h"
+#include "Delta.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/Metadata.h"
+
+using namespace llvm;
+
+/// Removes all aliases aren't inside any of the
+/// desired Chunks.
+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.");
+ });
+ if (HasDebugInfo && !O.shouldKeep())
+ StripDebugInfo(Program);
+}
+
+void llvm::stripDebugInfoDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, stripDebugInfoImpl, "Stripping Debug Info");
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.h
new file mode 100644
index 0000000..56be459
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/StripDebugInfo.h
@@ -0,0 +1,18 @@
+//===- StripDebugInfo.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_STRIPDEBUGINFO_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_STRIPDEBUGINFO_H
+
+#include "Delta.h"
+
+namespace llvm {
+void stripDebugInfoDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.cpp b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.cpp
index 0434eb7..669b9db 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.cpp
@@ -12,9 +12,29 @@
#include "Utils.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalIFunc.h"
using namespace llvm;
+extern cl::OptionCategory LLVMReduceOptions;
+
+cl::opt<bool> llvm::Verbose("verbose",
+ cl::desc("Print extra debugging information"),
+ cl::init(false), cl::cat(LLVMReduceOptions));
+
Value *llvm::getDefaultValue(Type *T) {
return T->isVoidTy() ? PoisonValue::get(T) : Constant::getNullValue(T);
}
+
+bool llvm::hasAliasUse(Function &F) {
+ return any_of(F.users(), [](User *U) {
+ return isa<GlobalAlias>(U) || isa<GlobalIFunc>(U);
+ });
+}
+
+bool llvm::hasAliasOrBlockAddressUse(Function &F) {
+ return any_of(F.users(), [](User *U) {
+ return isa<GlobalAlias, GlobalIFunc, BlockAddress>(U);
+ });
+}
diff --git a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.h b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.h
index e0c8f8e..e94aee5a 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.h
+++ b/src/llvm-project/llvm/tools/llvm-reduce/deltas/Utils.h
@@ -1,4 +1,4 @@
-//===- Utils.h - llvm-reduce utility functions ----------------------------===//
+//===- Utils.h - llvm-reduce utility functions ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -13,11 +13,17 @@
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_UTILS_H
#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_UTILS_H
+#include "llvm/IR/Function.h"
#include "llvm/IR/Value.h"
+#include "llvm/Support/CommandLine.h"
namespace llvm {
+extern cl::opt<bool> Verbose;
+
Value *getDefaultValue(Type *T);
+bool hasAliasUse(Function &F);
+bool hasAliasOrBlockAddressUse(Function &F);
} // namespace llvm
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 4d338f4..ace5c95 100644
--- a/src/llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp
+++ b/src/llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp
@@ -17,30 +17,21 @@
#include "DeltaManager.h"
#include "ReducerWorkItem.h"
#include "TestRunner.h"
-#include "llvm/Analysis/ProfileSummaryInfo.h"
-#include "llvm/Analysis/ModuleSummaryAnalysis.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/IRReader/IRReader.h"
-#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/IPO.h"
#include <system_error>
#include <vector>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
using namespace llvm;
cl::OptionCategory LLVMReduceOptions("llvm-reduce options");
@@ -50,18 +41,24 @@
static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden,
cl::cat(LLVMReduceOptions));
+static cl::opt<bool> PreserveDebugEnvironment(
+ "preserve-debug-environment",
+ cl::desc("Don't disable features used for crash "
+ "debugging (crash reports, llvm-symbolizer and core dumps)"),
+ cl::cat(LLVMReduceOptions));
+
static cl::opt<bool>
PrintDeltaPasses("print-delta-passes",
cl::desc("Print list of delta passes, passable to "
"--delta-passes as a comma separated list"),
cl::cat(LLVMReduceOptions));
-static cl::opt<std::string> InputFilename(cl::Positional, cl::Required,
+static cl::opt<std::string> InputFilename(cl::Positional,
cl::desc("<input llvm ll/bc file>"),
cl::cat(LLVMReduceOptions));
static cl::opt<std::string>
- TestFilename("test", cl::Required,
+ TestFilename("test",
cl::desc("Name of the interesting-ness test to be run"),
cl::cat(LLVMReduceOptions));
@@ -71,7 +68,8 @@
cl::cat(LLVMReduceOptions));
static cl::opt<std::string> OutputFilename(
- "output", cl::desc("Specify the output file. default: reduced.ll|mir"));
+ "output",
+ cl::desc("Specify the output file. default: reduced.ll|.bc|.mir"));
static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
cl::aliasopt(OutputFilename),
cl::cat(LLVMReduceOptions));
@@ -92,6 +90,11 @@
clEnumValN(InputLanguages::MIR, "mir", "")),
cl::cat(LLVMReduceOptions));
+static cl::opt<bool> ForceOutputBitcode(
+ "output-bitcode",
+ cl::desc("Emit final result as bitcode instead of text IR"), cl::Hidden,
+ cl::cat(LLVMReduceOptions));
+
static cl::opt<int>
MaxPassIterations("max-pass-iterations",
cl::desc("Maximum number of times to run the full set "
@@ -100,60 +103,57 @@
static codegen::RegisterCodeGenFlags CGF;
-void writeOutput(ReducerWorkItem &M, StringRef Message) {
- if (ReplaceInput) // In-place
+/// Turn off crash debugging features
+///
+/// Crash is expected, so disable crash reports and symbolization to reduce
+/// output clutter and avoid potentially slow symbolization.
+static void disableEnvironmentDebugFeatures() {
+ sys::Process::PreventCoreFiles();
+
+ // TODO: Copied from not. Should have a wrapper around setenv.
+#ifdef _WIN32
+ SetEnvironmentVariableA("LLVM_DISABLE_CRASH_REPORT", "1");
+ SetEnvironmentVariableA("LLVM_DISABLE_SYMBOLIZATION", "1");
+#else
+ setenv("LLVM_DISABLE_CRASH_REPORT", "1", /*overwrite=*/1);
+ setenv("LLVM_DISABLE_SYMBOLIZATION", "1", /*overwrite=*/1);
+#endif
+}
+
+static std::pair<StringRef, bool> determineOutputType(bool IsMIR,
+ bool InputIsBitcode) {
+ bool OutputBitcode = ForceOutputBitcode || InputIsBitcode;
+
+ if (ReplaceInput) { // In-place
OutputFilename = InputFilename.c_str();
- else if (OutputFilename.empty() || OutputFilename == "-")
- OutputFilename = M.isMIR() ? "reduced.mir" : "reduced.ll";
- std::error_code EC;
- raw_fd_ostream Out(OutputFilename, EC);
- if (EC) {
- errs() << "Error opening output file: " << EC.message() << "!\n";
- exit(1);
- }
- M.print(Out, /*AnnotationWriter=*/nullptr);
- errs() << Message << OutputFilename << "\n";
-}
+ } else if (OutputFilename.empty()) {
+ // Default to producing bitcode if the input was bitcode, if not explicitly
+ // requested.
-void writeBitcode(ReducerWorkItem &M, llvm::raw_ostream &OutStream) {
- if (M.LTOInfo && M.LTOInfo->IsThinLTO && M.LTOInfo->EnableSplitLTOUnit) {
- legacy::PassManager PM;
- PM.add(llvm::createWriteThinLTOBitcodePass(OutStream));
- PM.run(*(M.M));
- } else {
- std::unique_ptr<ModuleSummaryIndex> Index;
- if (M.LTOInfo && M.LTOInfo->HasSummary) {
- ProfileSummaryInfo PSI(M);
- Index = std::make_unique<ModuleSummaryIndex>(
- buildModuleSummaryIndex(M, nullptr, &PSI));
- }
- WriteBitcodeToFile(M, OutStream, Index.get());
+ OutputFilename =
+ IsMIR ? "reduced.mir" : (OutputBitcode ? "reduced.bc" : "reduced.ll");
}
-}
-void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx, const char *ToolName) {
- Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);
- if (!IF) {
- WithColor::error(errs(), ToolName) << IF.takeError();
- exit(1);
- }
- BitcodeModule BM = IF->Mods[0];
- Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
- Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);
- if (!LI || !MOrErr) {
- WithColor::error(errs(), ToolName) << IF.takeError();
- exit(1);
- }
- M.LTOInfo = std::make_unique<BitcodeLTOInfo>(*LI);
- M.M = std::move(MOrErr.get());
+ return {OutputFilename, OutputBitcode};
}
int main(int Argc, char **Argv) {
InitLLVM X(Argc, Argv);
+ const StringRef ToolName(Argv[0]);
cl::HideUnrelatedOptions({&LLVMReduceOptions, &getColorCategory()});
cl::ParseCommandLineOptions(Argc, Argv, "LLVM automatic testcase reducer.\n");
+ if (Argc == 1) {
+ cl::PrintHelpMessage();
+ return 0;
+ }
+
+ if (PrintDeltaPasses) {
+ printDeltaPasses(outs());
+ return 0;
+ }
+
bool ReduceModeMIR = false;
if (InputLanguage != InputLanguages::None) {
if (InputLanguage == InputLanguages::MIR)
@@ -162,23 +162,47 @@
ReduceModeMIR = true;
}
- if (PrintDeltaPasses) {
- printDeltaPasses(errs());
- return 0;
+ if (InputFilename.empty()) {
+ WithColor::error(errs(), ToolName)
+ << "reduction testcase positional argument must be specified\n";
+ return 1;
}
+ if (TestFilename.empty()) {
+ WithColor::error(errs(), ToolName) << "--test option must be specified\n";
+ return 1;
+ }
+
+ if (!PreserveDebugEnvironment)
+ disableEnvironmentDebugFeatures();
+
LLVMContext Context;
std::unique_ptr<TargetMachine> TM;
- std::unique_ptr<ReducerWorkItem> OriginalProgram =
- parseReducerWorkItem(Argv[0], InputFilename, Context, TM, ReduceModeMIR);
+ auto [OriginalProgram, InputIsBitcode] =
+ parseReducerWorkItem(ToolName, InputFilename, Context, TM, ReduceModeMIR);
if (!OriginalProgram) {
return 1;
}
+ StringRef OutputFilename;
+ bool OutputBitcode;
+ std::tie(OutputFilename, OutputBitcode) =
+ determineOutputType(ReduceModeMIR, InputIsBitcode);
+
// Initialize test environment
TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram),
- std::move(TM), Argv[0]);
+ std::move(TM), ToolName, OutputFilename, InputIsBitcode,
+ OutputBitcode);
+
+ // This parses and writes out the testcase into a temporary file copy for the
+ // test, rather than evaluating the source IR directly. This is for the
+ // convenience of lit tests; the stripped out comments may have broken the
+ // interestingness checks.
+ if (!Tester.getProgram().isReduced(Tester)) {
+ errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
+ return 1;
+ }
// Try to reduce code
runDeltaPasses(Tester, MaxPassIterations);
@@ -187,7 +211,7 @@
if (OutputFilename == "-")
Tester.getProgram().print(outs(), nullptr);
else
- writeOutput(Tester.getProgram(), "\nDone reducing! Reduced testcase: ");
+ Tester.writeOutput("Done reducing! Reduced testcase: ");
return 0;
}
diff --git a/src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp b/src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp
index ab59820..d97589e 100644
--- a/src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp
+++ b/src/llvm-project/llvm/tools/llvm-remark-size-diff/RemarkSizeDiff.cpp
@@ -15,7 +15,6 @@
//===----------------------------------------------------------------------===//
#include "llvm-c/Remarks.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Remarks/Remark.h"
@@ -404,13 +403,13 @@
InstCountA = InstCountB = StackSizeA = StackSizeB = 0;
switch (WhichFiles) {
case BOTH:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case A:
InstCountA = Diff.getInstCountA();
StackSizeA = Diff.getStackSizeA();
if (WhichFiles != BOTH)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case B:
InstCountB = Diff.getInstCountB();
StackSizeB = Diff.getStackSizeB();
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt
new file mode 100644
index 0000000..2def6b8
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS Core Demangle Object Remarks Support)
+
+add_llvm_tool(llvm-remarkutil
+ RemarkUtil.cpp
+)
diff --git a/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
new file mode 100644
index 0000000..0412eae
--- /dev/null
+++ b/src/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
@@ -0,0 +1,278 @@
+//===--------- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// 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 "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;
+
+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)");
+} // 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));
+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 {
+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(subopts::InstructionCount));
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
+} // namespace instructioncount
+
+/// \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);
+}
+
+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.
+ 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;
+ 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?");
+ 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
+
+/// 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();
+ return make_error<StringError>(
+ "Please specify a subcommand. (See -help for options)",
+ inconvertibleErrorCode());
+}
+
+int main(int argc, const 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());
+}
diff --git a/src/llvm-project/llvm/tools/llvm-rtdyld/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-rtdyld/CMakeLists.txt
index e173863..c7764ee 100644
--- a/src/llvm-project/llvm/tools/llvm-rtdyld/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-rtdyld/CMakeLists.txt
@@ -8,6 +8,7 @@
Object
RuntimeDyld
Support
+ TargetParser
)
add_llvm_tool(llvm-rtdyld
diff --git a/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt
index 8e2b78f..90e2904 100644
--- a/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -39,6 +39,7 @@
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "DragonFly")
+ OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")) # FIXME: It should be "GNU ld for elf"
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/simple_version_script.map.in
@@ -63,6 +64,10 @@
target_link_libraries(LLVM PRIVATE ${LIB_NAMES})
+ if(LLVM_ENABLE_THREADS AND NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
+ target_link_libraries(LLVM PUBLIC atomic)
+ endif()
+
if (APPLE)
set_property(TARGET LLVM APPEND_STRING PROPERTY
LINK_FLAGS
@@ -88,7 +93,7 @@
set(LLVM_EXPORTED_SYMBOL_FILE ${LLVM_BINARY_DIR}/libllvm-c.exports)
- set(LIB_DIR ${LLVM_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+ set(LIB_DIR ${LLVM_LIBRARY_DIR})
set(LIB_NAME ${LIB_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}LLVM)
set(LIB_PATH ${LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
set(LIB_EXPORTS_PATH ${LIB_NAME}.exports)
@@ -136,7 +141,7 @@
# Get the full name to the libs so the python script understands them.
foreach(lib ${LIB_NAMES})
- list(APPEND FULL_LIB_NAMES ${LLVM_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib/${lib}.lib)
+ list(APPEND FULL_LIB_NAMES ${LLVM_LIBRARY_DIR}/${lib}.lib)
endforeach()
# Need to separate lib names with newlines.
diff --git a/src/llvm-project/llvm/tools/llvm-sim/llvm-sim.cpp b/src/llvm-project/llvm/tools/llvm-sim/llvm-sim.cpp
index 2b717d7..d09e515 100644
--- a/src/llvm-project/llvm/tools/llvm-sim/llvm-sim.cpp
+++ b/src/llvm-project/llvm/tools/llvm-sim/llvm-sim.cpp
@@ -41,13 +41,13 @@
/// \param LLVMInstNum - The mapping of Instructions to their location in the
/// module represented by an unsigned integer.
/// \returns The instruction number for \p I if it exists.
-Optional<unsigned>
+std::optional<unsigned>
getPositionInModule(const Instruction *I,
const DenseMap<Instruction *, unsigned> &LLVMInstNum) {
assert(I && "Instruction is nullptr!");
DenseMap<Instruction *, unsigned>::const_iterator It = LLVMInstNum.find(I);
if (It == LLVMInstNum.end())
- return None;
+ return std::nullopt;
return It->second;
}
@@ -80,9 +80,9 @@
// For each file there is a list of the range where the similarity
// exists.
for (const IRSimilarityCandidate &C : G) {
- Optional<unsigned> Start =
+ std::optional<unsigned> Start =
getPositionInModule((*C.front()).Inst, LLVMInstNum);
- Optional<unsigned> End =
+ std::optional<unsigned> End =
getPositionInModule((*C.back()).Inst, LLVMInstNum);
assert(Start &&
@@ -90,8 +90,8 @@
assert(End && "Could not find instruction number for last instruction");
J.object([&] {
- J.attribute("start", Start.value());
- J.attribute("end", End.value());
+ J.attribute("start", *Start);
+ J.attribute("end", *End);
});
}
J.arrayEnd();
diff --git a/src/llvm-project/llvm/tools/llvm-size/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-size/CMakeLists.txt
index 0d1f660..a837ba6 100644
--- a/src/llvm-project/llvm/tools/llvm-size/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-size/CMakeLists.txt
@@ -2,6 +2,7 @@
Object
Option
Support
+ TargetParser
)
set(LLVM_TARGET_DEFINITIONS Opts.td)
@@ -12,6 +13,7 @@
llvm-size.cpp
DEPENDS
SizeOptsTableGen
+ GENERATE_DRIVER
)
if(LLVM_INSTALL_BINUTILS_SYMLINKS)
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 1c7484b..32dbf3d 100644
--- a/src/llvm-project/llvm/tools/llvm-size/llvm-size.cpp
+++ b/src/llvm-project/llvm/tools/llvm-size/llvm-size.cpp
@@ -47,11 +47,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -63,9 +66,9 @@
#undef OPTION
};
-class SizeOptTable : public opt::OptTable {
+class SizeOptTable : public opt::GenericOptTable {
public:
- SizeOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+ SizeOptTable() : GenericOptTable(InfoTable) { setGroupedShortOptions(true); }
};
enum OutputFormatTy { berkeley, sysv, darwin };
@@ -570,6 +573,8 @@
else if (MachO && OutputFormat == darwin)
outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
printObjectSectionSizes(o);
+ if (!MachO && OutputFormat == darwin)
+ outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
if (OutputFormat == berkeley) {
if (MachO)
outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
@@ -836,6 +841,8 @@
else if (MachO && OutputFormat == darwin && MoreThanOneFile)
outs() << o->getFileName() << ":\n";
printObjectSectionSizes(o);
+ if (!MachO && OutputFormat == darwin)
+ outs() << o->getFileName() << "\n";
if (OutputFormat == berkeley) {
if (!MachO || MoreThanOneFile)
outs() << o->getFileName();
@@ -862,7 +869,7 @@
<< "(TOTALS)\n";
}
-int main(int argc, char **argv) {
+int llvm_size_main(int argc, char **argv) {
InitLLVM X(argc, argv);
BumpPtrAllocator A;
StringSaver Saver(A);
@@ -937,4 +944,5 @@
if (HadError)
return 1;
+ 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 e15d1d6..639506c 100644
--- a/src/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp
+++ b/src/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp
@@ -24,17 +24,14 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
-#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
@@ -74,6 +71,12 @@
cl::desc("Additional IR scalar types "
"(always includes i1, i8, i16, i32, i64, float and double)"));
+static cl::opt<bool> EnableScalableVectors(
+ "enable-scalable-vectors",
+ cl::desc("Generate IR involving scalable vector types"),
+ cl::init(false), cl::cat(StressCategory));
+
+
namespace {
/// A utility class to provide a pseudo-random number generator which is
@@ -242,9 +245,7 @@
if (getRandom() & 1)
return ConstantFP::getAllOnesValue(Tp);
return ConstantFP::getNullValue(Tp);
- } else if (Tp->isVectorTy()) {
- auto *VTp = cast<FixedVectorType>(Tp);
-
+ } else if (auto *VTp = dyn_cast<FixedVectorType>(Tp)) {
std::vector<Constant*> TempValues;
TempValues.reserve(VTp->getNumElements());
for (unsigned i = 0; i < VTp->getNumElements(); ++i)
@@ -291,21 +292,26 @@
}
/// Pick a random vector type.
- Type *pickVectorType(unsigned len = (unsigned)-1) {
- // Pick a random vector width in the range 2**0 to 2**4.
- // by adding two randoms we are generating a normal-like distribution
- // around 2**3.
- unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3));
- Type *Ty;
+ Type *pickVectorType(VectorType *VTy = nullptr) {
// Vectors of x86mmx are illegal; keep trying till we get something else.
+ Type *Ty;
do {
Ty = pickScalarType();
} while (Ty->isX86_MMXTy());
- if (len != (unsigned)-1)
- width = len;
- return FixedVectorType::get(Ty, width);
+ if (VTy)
+ return VectorType::get(Ty, VTy->getElementCount());
+
+ // Select either fixed length or scalable vectors with 50% probability
+ // (only if scalable vectors are enabled)
+ bool Scalable = EnableScalableVectors && getRandom() & 1;
+
+ // Pick a random vector width in the range 2**0 to 2**4.
+ // by adding two randoms we are generating a normal-like distribution
+ // around 2**3.
+ unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3));
+ return VectorType::get(Ty, width, Scalable);
}
/// Pick a random scalar type.
@@ -432,7 +438,7 @@
for (unsigned i = 0; i < 2; ++i)
RandomBits[i] = Ran->Rand64();
- APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits));
+ APInt RandomInt(Ty->getPrimitiveSizeInBits(), ArrayRef(RandomBits));
APFloat RandomFloat(Ty->getFltSemantics(), RandomInt);
if (getRandom() & 1)
@@ -479,10 +485,7 @@
Value *Val0 = getRandomVectorValue();
Value *V = ExtractElementInst::Create(
Val0,
- ConstantInt::get(
- Type::getInt32Ty(BB->getContext()),
- getRandom() %
- cast<FixedVectorType>(Val0->getType())->getNumElements()),
+ getRandomValue(Type::getInt32Ty(BB->getContext())),
"E", BB->getTerminator());
return PT->push_back(V);
}
@@ -496,6 +499,10 @@
Value *Val0 = getRandomVectorValue();
Value *Val1 = getRandomValue(Val0->getType());
+ // Can't express arbitrary shufflevectors for scalable vectors
+ if (isa<ScalableVectorType>(Val0->getType()))
+ return;
+
unsigned Width = cast<FixedVectorType>(Val0->getType())->getNumElements();
std::vector<Constant*> Idxs;
@@ -526,10 +533,7 @@
Value *V = InsertElementInst::Create(
Val0, Val1,
- ConstantInt::get(
- Type::getInt32Ty(BB->getContext()),
- getRandom() %
- cast<FixedVectorType>(Val0->getType())->getNumElements()),
+ getRandomValue(Type::getInt32Ty(BB->getContext())),
"I", BB->getTerminator());
return PT->push_back(V);
}
@@ -545,10 +549,8 @@
Type *DestTy = pickScalarType();
// Handle vector casts vectors.
- if (VTy->isVectorTy()) {
- auto *VecTy = cast<FixedVectorType>(VTy);
- DestTy = pickVectorType(VecTy->getNumElements());
- }
+ if (VTy->isVectorTy())
+ DestTy = pickVectorType(cast<VectorType>(VTy));
// no need to cast.
if (VTy == DestTy) return;
@@ -628,11 +630,9 @@
// If the value type is a vector, and we allow vector select, then in 50%
// of the cases generate a vector select.
- if (isa<FixedVectorType>(Val0->getType()) && (getRandom() & 1)) {
- unsigned NumElem =
- cast<FixedVectorType>(Val0->getType())->getNumElements();
- CondTy = FixedVectorType::get(CondTy, NumElem);
- }
+ if (auto *VTy = dyn_cast<VectorType>(Val0->getType()))
+ if (getRandom() & 1)
+ CondTy = VectorType::get(CondTy, VTy->getElementCount());
Value *Cond = getRandomValue(CondTy);
Value *V = SelectInst::Create(Cond, Val0, Val1, "Sl", BB->getTerminator());
@@ -761,10 +761,13 @@
return 1;
}
- legacy::PassManager Passes;
- Passes.add(createVerifierPass());
- Passes.add(createPrintModulePass(Out->os()));
- Passes.run(*M.get());
+ // Check that the generated module is accepted by the verifier.
+ if (verifyModule(*M.get(), &Out->os()))
+ report_fatal_error("Broken module found, compilation aborted!");
+
+ // Output textual IR.
+ M->print(Out->os(), nullptr);
+
Out->keep();
return 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 71d1321e..f6d08a1 100644
--- a/src/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp
+++ b/src/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp
@@ -39,11 +39,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -55,9 +58,11 @@
#undef OPTION
};
-class StringsOptTable : public opt::OptTable {
+class StringsOptTable : public opt::GenericOptTable {
public:
- StringsOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+ StringsOptTable() : GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
};
} // namespace
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 34c93be..ed24e85 100644
--- a/src/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/src/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -23,7 +23,7 @@
#include "llvm/DebugInfo/Symbolize/MarkupFilter.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
-#include "llvm/Debuginfod/DIFetcher.h"
+#include "llvm/Debuginfod/BuildIDFetcher.h"
#include "llvm/Debuginfod/Debuginfod.h"
#include "llvm/Debuginfod/HTTPClient.h"
#include "llvm/Option/Arg.h"
@@ -40,6 +40,7 @@
#include <algorithm>
#include <cstdio>
#include <cstring>
+#include <iostream>
#include <string>
using namespace llvm;
@@ -55,11 +56,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -71,9 +75,9 @@
#undef OPTION
};
-class SymbolizerOptTable : public opt::OptTable {
+class SymbolizerOptTable : public opt::GenericOptTable {
public:
- SymbolizerOptTable() : OptTable(InfoTable) {
+ SymbolizerOptTable() : GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};
@@ -108,30 +112,31 @@
Frame,
};
-static void enableDebuginfod(LLVMSymbolizer &Symbolizer) {
+static void enableDebuginfod(LLVMSymbolizer &Symbolizer,
+ const opt::ArgList &Args) {
static bool IsEnabled = false;
if (IsEnabled)
return;
IsEnabled = true;
// Look up symbols using the debuginfod client.
- Symbolizer.addDIFetcher(std::make_unique<DebuginfodDIFetcher>());
+ Symbolizer.setBuildIDFetcher(std::make_unique<DebuginfodFetcher>(
+ Args.getAllArgValues(OPT_debug_file_directory_EQ)));
// The HTTPClient must be initialized for use by the debuginfod client.
HTTPClient::initialize();
}
-static SmallVector<uint8_t> parseBuildID(StringRef Str) {
+static object::BuildID parseBuildID(StringRef Str) {
std::string Bytes;
if (!tryGetFromHex(Str, Bytes))
return {};
ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
Bytes.size());
- return SmallVector<uint8_t>(BuildID.begin(), BuildID.end());
+ return object::BuildID(BuildID.begin(), BuildID.end());
}
static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
StringRef InputString, Command &Cmd,
- std::string &ModuleName,
- SmallVectorImpl<uint8_t> &BuildID,
+ std::string &ModuleName, object::BuildID &BuildID,
uint64_t &ModuleOffset) {
const char kDelimiters[] = " \n\r";
ModuleName = "";
@@ -248,24 +253,24 @@
}
static void symbolizeInput(const opt::InputArgList &Args,
- ArrayRef<uint8_t> IncomingBuildID,
+ object::BuildIDRef IncomingBuildID,
uint64_t AdjustVMA, bool IsAddr2Line,
OutputStyle Style, StringRef InputString,
LLVMSymbolizer &Symbolizer, DIPrinter &Printer) {
Command Cmd;
std::string ModuleName;
- SmallVector<uint8_t> BuildID(IncomingBuildID.begin(), IncomingBuildID.end());
+ 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, None}, InputString);
+ Printer.printInvalidCommand({ModuleName, std::nullopt}, InputString);
return;
}
bool ShouldInline = Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line);
if (!BuildID.empty()) {
assert(ModuleName.empty());
if (!Args.hasArg(OPT_no_debuginfod))
- enableDebuginfod(Symbolizer);
+ enableDebuginfod(Symbolizer, Args);
std::string BuildIDStr = toHex(BuildID);
executeCommand(BuildIDStr, BuildID, Cmd, Offset, AdjustVMA, ShouldInline,
Style, Symbolizer, Printer);
@@ -339,25 +344,24 @@
return IsAddr2Line ? FunctionNameKind::None : FunctionNameKind::LinkageName;
}
-static Optional<bool> parseColorArg(const opt::InputArgList &Args) {
+static std::optional<bool> parseColorArg(const opt::InputArgList &Args) {
if (Args.hasArg(OPT_color))
return true;
if (const opt::Arg *A = Args.getLastArg(OPT_color_EQ))
- return StringSwitch<Optional<bool>>(A->getValue())
+ return StringSwitch<std::optional<bool>>(A->getValue())
.Case("always", true)
.Case("never", false)
- .Case("auto", None);
- return None;
+ .Case("auto", std::nullopt);
+ return std::nullopt;
}
-static SmallVector<uint8_t> parseBuildIDArg(const opt::InputArgList &Args,
- int ID) {
+static object::BuildID parseBuildIDArg(const opt::InputArgList &Args, int ID) {
const opt::Arg *A = Args.getLastArg(ID);
if (!A)
return {};
StringRef V(A->getValue());
- SmallVector<uint8_t> BuildID = parseBuildID(V);
+ object::BuildID BuildID = parseBuildID(V);
if (BuildID.empty()) {
errs() << A->getSpelling() + ": expected a build ID, but got '" + V + "'\n";
exit(1);
@@ -439,14 +443,8 @@
LLVMSymbolizer Symbolizer(Opts);
- // A debuginfod lookup could succeed if a HTTP client is available and at
- // least one backing URL is configured.
- bool ShouldUseDebuginfodByDefault =
- HTTPClient::isAvailable() &&
- !ExitOnErr(getDefaultDebuginfodUrls()).empty();
- if (Args.hasFlag(OPT_debuginfod, OPT_no_debuginfod,
- ShouldUseDebuginfodByDefault))
- enableDebuginfod(Symbolizer);
+ if (Args.hasFlag(OPT_debuginfod, OPT_no_debuginfod, canUseDebuginfod()))
+ enableDebuginfod(Symbolizer, Args);
if (Args.hasArg(OPT_filter_markup)) {
filterMarkup(Args, Symbolizer);
@@ -467,7 +465,7 @@
errs() << "error: cannot specify both --build-id and --obj\n";
return EXIT_FAILURE;
}
- SmallVector<uint8_t> BuildID = parseBuildIDArg(Args, OPT_build_id_EQ);
+ object::BuildID BuildID = parseBuildIDArg(Args, OPT_build_id_EQ);
std::unique_ptr<DIPrinter> Printer;
if (Style == OutputStyle::GNU)
diff --git a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp b/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
index 45a1f78..9ebaadb 100644
--- a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
+++ b/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
@@ -235,12 +235,11 @@
Result.Kind = AD_Str_Vec;
for (const auto &IRef : CollectedIRefVec)
for (auto Targ : IRef.targets()) {
- auto FoundIRef = llvm::find_if(LookupIRefVec, [&](const auto LIRef) {
- auto FoundTarg = llvm::find(LIRef.targets(), Targ);
- return (FoundTarg != LIRef.targets().end() &&
- IRef.getInstallName() == LIRef.getInstallName());
+ auto FoundIRef = llvm::any_of(LookupIRefVec, [&](const auto LIRef) {
+ return llvm::is_contained(LIRef.targets(), Targ) &&
+ IRef.getInstallName() == LIRef.getInstallName();
});
- if (FoundIRef == LookupIRefVec.end())
+ if (!FoundIRef)
addDiffForTargSlice<DiffStrVec,
DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
IRef.getInstallName(), Targ, Result, Order);
@@ -267,14 +266,13 @@
Result.Kind = AD_Sym_Vec;
for (const auto *Sym : CollectedSyms)
for (const auto Targ : Sym->targets()) {
- auto FoundSym = llvm::find_if(LookupSyms, [&](const auto LSym) {
- auto FoundTarg = llvm::find(LSym->targets(), Targ);
+ auto FoundSym = llvm::any_of(LookupSyms, [&](const auto LSym) {
return (Sym->getName() == LSym->getName() &&
Sym->getKind() == LSym->getKind() &&
Sym->getFlags() == LSym->getFlags() &&
- FoundTarg != LSym->targets().end());
+ llvm::is_contained(LSym->targets(), Targ));
});
- if (FoundSym == LookupSyms.end())
+ if (!FoundSym)
addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Result, Order);
}
}
@@ -410,10 +408,10 @@
}
for (auto DocRHS : IFRHS->documents()) {
auto WasGathered =
- llvm::find_if(DocsInserted, [&](const auto &GatheredDoc) {
+ llvm::any_of(DocsInserted, [&](const auto &GatheredDoc) {
return (GatheredDoc == DocRHS->getInstallName());
});
- if (WasGathered == DocsInserted.end())
+ if (!WasGathered)
Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
DocRHS->getInstallName(), getSingleIF(DocRHS.get(), rhs))));
}
diff --git a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h b/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h
index 252fbd8..e486405 100644
--- a/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h
+++ b/src/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h
@@ -13,7 +13,6 @@
#ifndef LLVM_TOOLS_LLVM_TAPI_DIFF_DIFFENGINE_H
#define LLVM_TOOLS_LLVM_TAPI_DIFF_DIFFENGINE_H
-#include "llvm/ADT/Optional.h"
#include "llvm/Object/TapiUniversal.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TextAPI/Symbol.h"
diff --git a/src/llvm-project/llvm/tools/llvm-tli-checker/CMakeLists.txt b/src/llvm-project/llvm/tools/llvm-tli-checker/CMakeLists.txt
index 9be44e4..384c09d 100644
--- a/src/llvm-project/llvm/tools/llvm-tli-checker/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/llvm-tli-checker/CMakeLists.txt
@@ -11,6 +11,7 @@
Option
Remarks
Support
+ TargetParser
TextAPI
)
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 7deeaef..179c42b 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
@@ -35,11 +35,14 @@
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#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 const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
@@ -51,9 +54,9 @@
#undef OPTION
};
-class TLICheckerOptTable : public opt::OptTable {
+class TLICheckerOptTable : public opt::GenericOptTable {
public:
- TLICheckerOptTable() : OptTable(InfoTable) {}
+ TLICheckerOptTable() : GenericOptTable(InfoTable) {}
};
} // end anonymous namespace
@@ -155,6 +158,7 @@
// Store all the exported symbol names we found in the input libraries.
// We use a map to get hashed lookup speed; the bool is meaningless.
class SDKNameMap : public StringMap<bool> {
+ void maybeInsertSymbol(const SymbolRef &S, const ObjectFile &O);
void populateFromObject(ObjectFile *O);
void populateFromArchive(Archive *A);
@@ -163,6 +167,19 @@
};
static SDKNameMap SDKNames;
+// Insert defined global function symbols into the map if valid.
+void SDKNameMap::maybeInsertSymbol(const SymbolRef &S, const ObjectFile &O) {
+ SymbolRef::Type Type = unwrapIgnoreError(S.getType());
+ uint32_t Flags = unwrapIgnoreError(S.getFlags());
+ section_iterator Section = unwrapIgnoreError(S.getSection(),
+ /*Default=*/O.section_end());
+ if (Type == SymbolRef::ST_Function && (Flags & SymbolRef::SF_Global) &&
+ Section != O.section_end()) {
+ StringRef Name = unwrapIgnoreError(S.getName());
+ insert({ Name, true });
+ }
+}
+
// Given an ObjectFile, extract the global function symbols.
void SDKNameMap::populateFromObject(ObjectFile *O) {
// FIXME: Support other formats.
@@ -173,16 +190,12 @@
}
const auto *ELF = cast<ELFObjectFileBase>(O);
- for (auto &S : ELF->getDynamicSymbolIterators()) {
- // We want only defined global function symbols.
- SymbolRef::Type Type = unwrapIgnoreError(S.getType());
- uint32_t Flags = unwrapIgnoreError(S.getFlags());
- section_iterator Section = unwrapIgnoreError(S.getSection(),
- /*Default=*/O->section_end());
- StringRef Name = unwrapIgnoreError(S.getName());
- if (Type == SymbolRef::ST_Function && (Flags & SymbolRef::SF_Global) &&
- Section != O->section_end())
- insert({Name, true});
+ if (ELF->getEType() == ELF::ET_REL) {
+ for (const auto &S : ELF->symbols())
+ maybeInsertSymbol(S, *O);
+ } else {
+ for (const auto &S : ELF->getDynamicSymbolIterators())
+ maybeInsertSymbol(S, *O);
}
}
@@ -191,7 +204,7 @@
void SDKNameMap::populateFromArchive(Archive *A) {
Error Err = Error::success();
int Index = -1;
- for (auto &C : A->children(Err)) {
+ for (const auto &C : A->children(Err)) {
++Index;
Expected<std::unique_ptr<object::Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
diff --git a/src/llvm-project/llvm/tools/llvm-xray/llvm-xray.cpp b/src/llvm-project/llvm/tools/llvm-xray/llvm-xray.cpp
index 9ee653e..2b1182c 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/llvm-xray.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/llvm-xray.cpp
@@ -31,7 +31,7 @@
if (*SC) {
// If no subcommand was provided, we need to explicitly check if this is
// the top-level subcommand.
- if (SC == &*cl::TopLevelSubCommand) {
+ if (SC == &cl::SubCommand::getTopLevel()) {
cl::PrintHelpMessage(false, true);
return 0;
}
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-account.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-account.cpp
index 1117046..a9d9129 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-account.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-account.cpp
@@ -23,6 +23,8 @@
#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
+#include <cmath>
+
using namespace llvm;
using namespace llvm::xray;
@@ -201,10 +203,10 @@
// Look for the parent up the stack.
auto Parent =
- std::find_if(ThreadStack.Stack.rbegin(), ThreadStack.Stack.rend(),
- [&](const std::pair<const int32_t, uint64_t> &E) {
- return E.first == Record.FuncId;
- });
+ llvm::find_if(llvm::reverse(ThreadStack.Stack),
+ [&](const std::pair<const int32_t, uint64_t> &E) {
+ return E.first == Record.FuncId;
+ });
if (Parent == ThreadStack.Stack.rend())
return false;
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 371a9cc..38d3ec9 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-account.h
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-account.h
@@ -45,7 +45,7 @@
RecursionStatus &operator--();
bool isRecursive() const;
};
- Optional<llvm::DenseMap<int32_t, RecursionStatus>> RecursionDepth;
+ std::optional<llvm::DenseMap<int32_t, RecursionStatus>> RecursionDepth;
};
typedef llvm::DenseMap<uint32_t, FunctionStack> PerThreadFunctionStackMap;
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-color-helper.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-color-helper.cpp
index b2ed638..3dd5143 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-color-helper.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-color-helper.cpp
@@ -111,7 +111,7 @@
// Takes a double precision number, clips it between 0 and 1 and then converts
// that to an integer between 0x00 and 0xFF with proxpper rounding.
static uint8_t unitIntervalTo8BitChar(double B) {
- double n = std::max(std::min(B, 1.0), 0.0);
+ double n = std::clamp(B, 0.0, 1.0);
return static_cast<uint8_t>(255 * n + 0.5);
}
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 bcadade..8ccfd30 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
@@ -264,7 +264,7 @@
const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
double RelDiff = statRelDiff(LeftStat, RightStat, T);
- double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
+ double CappedRelDiff = std::clamp(RelDiff, -1.0, 1.0);
return H.getColorString(CappedRelDiff);
}
@@ -285,7 +285,7 @@
const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
double RelDiff = statRelDiff(LeftStat, RightStat, T);
- double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
+ double CappedRelDiff = std::clamp(RelDiff, -1.0, 1.0);
return H.getColorString(CappedRelDiff);
}
diff --git a/src/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp b/src/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp
index ff47eb6..b832805 100644
--- a/src/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp
+++ b/src/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp
@@ -17,6 +17,8 @@
#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
+#include <cmath>
+
using namespace llvm;
using namespace llvm::xray;
diff --git a/src/llvm-project/llvm/tools/lto/lto.cpp b/src/llvm-project/llvm/tools/lto/lto.cpp
index ff5c2c6..22ebf54 100644
--- a/src/llvm-project/llvm/tools/lto/lto.cpp
+++ b/src/llvm-project/llvm/tools/lto/lto.cpp
@@ -290,6 +290,8 @@
codegen::InitTargetOptionsFromCodeGenFlags(Triple());
ErrorOr<std::unique_ptr<LTOModule>> M = LTOModule::createFromBuffer(
unwrap(cg)->getContext(), mem, length, Options, StringRef(path));
+ if (!M)
+ return nullptr;
return wrap(M->release());
}
@@ -394,7 +396,7 @@
unwrap(cg)->setCodePICModel(Reloc::DynamicNoPIC);
return false;
case LTO_CODEGEN_PIC_MODEL_DEFAULT:
- unwrap(cg)->setCodePICModel(None);
+ unwrap(cg)->setCodePICModel(std::nullopt);
return false;
}
sLastErrorString = "Unknown PIC model";
@@ -494,7 +496,7 @@
SmallVector<StringRef, 4> Options;
for (int i = 0; i < number; ++i)
Options.push_back(options[i]);
- unwrap(cg)->setCodeGenDebugOptions(makeArrayRef(Options));
+ unwrap(cg)->setCodeGenDebugOptions(ArrayRef(Options));
}
unsigned int lto_api_version() { return LTO_API_VERSION; }
@@ -526,20 +528,10 @@
if (OptLevel < '0' || OptLevel > '3')
report_fatal_error("Optimization level must be between 0 and 3");
CodeGen->setOptLevel(OptLevel - '0');
- switch (OptLevel) {
- case '0':
- CodeGen->setCodeGenOptLevel(CodeGenOpt::None);
- break;
- case '1':
- CodeGen->setCodeGenOptLevel(CodeGenOpt::Less);
- break;
- case '2':
- CodeGen->setCodeGenOptLevel(CodeGenOpt::Default);
- break;
- case '3':
- CodeGen->setCodeGenOptLevel(CodeGenOpt::Aggressive);
- break;
- }
+ std::optional<CodeGenOpt::Level> CGOptLevelOrNone =
+ CodeGenOpt::getLevel(OptLevel - '0');
+ assert(CGOptLevelOrNone);
+ CodeGen->setCodeGenOptLevel(*CGOptLevelOrNone);
}
return wrap(CodeGen);
}
@@ -671,7 +663,7 @@
unwrap(cg)->setCodePICModel(Reloc::DynamicNoPIC);
return false;
case LTO_CODEGEN_PIC_MODEL_DEFAULT:
- unwrap(cg)->setCodePICModel(None);
+ unwrap(cg)->setCodePICModel(std::nullopt);
return false;
}
sLastErrorString = "Unknown PIC model";
diff --git a/src/llvm-project/llvm/tools/lto/lto.exports b/src/llvm-project/llvm/tools/lto/lto.exports
index 3abae5f..4164c39 100644
--- a/src/llvm-project/llvm/tools/lto/lto.exports
+++ b/src/llvm-project/llvm/tools/lto/lto.exports
@@ -45,12 +45,6 @@
lto_codegen_set_should_internalize
lto_codegen_set_should_embed_uselists
lto_set_debug_options
-LLVMCreateDisasm
-LLVMCreateDisasmCPU
-LLVMDisasmDispose
-LLVMDisasmInstruction
-LLVMSetDisasmOptions
-LLVMCreateDisasmCPUFeatures
thinlto_create_codegen
thinlto_codegen_dispose
thinlto_codegen_add_module
diff --git a/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp
index 2426705..4c4ae3f 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/dwarf2yaml.cpp
@@ -18,6 +18,7 @@
#include "llvm/ObjectYAML/DWARFYAML.h"
#include <algorithm>
+#include <optional>
using namespace llvm;
@@ -165,7 +166,7 @@
return ErrorSuccess();
}
-static Optional<DWARFYAML::PubSection>
+static std::optional<DWARFYAML::PubSection>
dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
bool IsGNUStyle) {
DWARFYAML::PubSection Y;
@@ -178,7 +179,7 @@
[](Error Err) { consumeError(std::move(Err)); });
ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData();
if (Sets.empty())
- return None;
+ return std::nullopt;
// FIXME: Currently, obj2yaml only supports dumping the first pubtable.
Y.Format = Sets[0].Format;
@@ -247,15 +248,15 @@
auto FormValue = DIEWrapper.find(AttrSpec.Attr);
if (!FormValue)
return;
- auto Form = FormValue.value().getForm();
+ auto Form = FormValue->getForm();
bool indirect = false;
do {
indirect = false;
switch (Form) {
case dwarf::DW_FORM_addr:
case dwarf::DW_FORM_GNU_addr_index:
- if (auto Val = FormValue.value().getAsAddress())
- NewValue.Value = Val.value();
+ if (auto Val = FormValue->getAsAddress())
+ NewValue.Value = *Val;
break;
case dwarf::DW_FORM_ref_addr:
case dwarf::DW_FORM_ref1:
@@ -264,16 +265,16 @@
case dwarf::DW_FORM_ref8:
case dwarf::DW_FORM_ref_udata:
case dwarf::DW_FORM_ref_sig8:
- if (auto Val = FormValue.value().getAsReferenceUVal())
- NewValue.Value = Val.value();
+ if (auto Val = FormValue->getAsReferenceUVal())
+ NewValue.Value = *Val;
break;
case dwarf::DW_FORM_exprloc:
case dwarf::DW_FORM_block:
case dwarf::DW_FORM_block1:
case dwarf::DW_FORM_block2:
case dwarf::DW_FORM_block4:
- if (auto Val = FormValue.value().getAsBlock()) {
- auto BlockData = Val.value();
+ if (auto Val = FormValue->getAsBlock()) {
+ auto BlockData = *Val;
std::copy(BlockData.begin(), BlockData.end(),
std::back_inserter(NewValue.BlockData));
}
@@ -288,8 +289,8 @@
case dwarf::DW_FORM_udata:
case dwarf::DW_FORM_ref_sup4:
case dwarf::DW_FORM_ref_sup8:
- if (auto Val = FormValue.value().getAsUnsignedConstant())
- NewValue.Value = Val.value();
+ if (auto Val = FormValue->getAsUnsignedConstant())
+ NewValue.Value = *Val;
break;
case dwarf::DW_FORM_string:
if (auto Val = dwarf::toString(FormValue))
@@ -297,10 +298,10 @@
break;
case dwarf::DW_FORM_indirect:
indirect = true;
- if (auto Val = FormValue.value().getAsUnsignedConstant()) {
- NewValue.Value = Val.value();
+ if (auto Val = FormValue->getAsUnsignedConstant()) {
+ NewValue.Value = *Val;
NewEntry.Values.push_back(NewValue);
- Form = static_cast<dwarf::Form>(Val.value());
+ Form = static_cast<dwarf::Form>(*Val);
}
break;
case dwarf::DW_FORM_strp:
@@ -311,8 +312,8 @@
case dwarf::DW_FORM_strp_sup:
case dwarf::DW_FORM_GNU_str_index:
case dwarf::DW_FORM_strx:
- if (auto Val = FormValue.value().getAsCStringOffset())
- NewValue.Value = Val.value();
+ if (auto Val = FormValue->getAsCStringOffset())
+ NewValue.Value = *Val;
break;
case dwarf::DW_FORM_flag_present:
NewValue.Value = 1;
diff --git a/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
index 122ae7d..462d87a 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp
@@ -38,23 +38,43 @@
Obj->Header.PartOffsets = std::vector<uint32_t>();
for (const auto P : Container) {
Obj->Header.PartOffsets->push_back(P.Offset);
- if (P.Part.getName() == "DXIL") {
- Optional<DXContainer::DXILData> DXIL = Container.getDXIL();
+ Obj->Parts.push_back(
+ DXContainerYAML::Part(P.Part.getName().str(), P.Part.Size));
+ DXContainerYAML::Part &NewPart = Obj->Parts.back();
+ dxbc::PartType PT = dxbc::parsePartType(P.Part.getName());
+ switch (PT) {
+ case dxbc::PartType::DXIL: {
+ std::optional<DXContainer::DXILData> DXIL = Container.getDXIL();
assert(DXIL && "Since we are iterating and found a DXIL part, "
"this should never not have a value");
- Obj->Parts.push_back(DXContainerYAML::Part{
- P.Part.getName().str(), P.Part.Size,
- DXContainerYAML::DXILProgram{
- DXIL->first.MajorVersion, DXIL->first.MinorVersion,
- DXIL->first.ShaderKind, DXIL->first.Size,
- DXIL->first.Bitcode.MajorVersion,
- DXIL->first.Bitcode.MinorVersion, DXIL->first.Bitcode.Offset,
- DXIL->first.Bitcode.Size,
- std::vector<llvm::yaml::Hex8>(
- DXIL->second, DXIL->second + DXIL->first.Bitcode.Size)}});
- } else {
- Obj->Parts.push_back(
- DXContainerYAML::Part{P.Part.getName().str(), P.Part.Size, None});
+ NewPart.Program = DXContainerYAML::DXILProgram{
+ DXIL->first.MajorVersion,
+ DXIL->first.MinorVersion,
+ DXIL->first.ShaderKind,
+ DXIL->first.Size,
+ DXIL->first.Bitcode.MajorVersion,
+ DXIL->first.Bitcode.MinorVersion,
+ DXIL->first.Bitcode.Offset,
+ DXIL->first.Bitcode.Size,
+ std::vector<llvm::yaml::Hex8>(
+ DXIL->second, DXIL->second + DXIL->first.Bitcode.Size)};
+ break;
+ }
+ case dxbc::PartType::SFI0: {
+ std::optional<uint64_t> Flags = Container.getShaderFlags();
+ // Omit the flags in the YAML if they are missing or zero.
+ if (Flags && *Flags > 0)
+ NewPart.Flags = DXContainerYAML::ShaderFlags(*Flags);
+ break;
+ }
+ case dxbc::PartType::HASH: {
+ std::optional<dxbc::ShaderHash> Hash = Container.getShaderHash();
+ if (Hash && Hash->isPopulated())
+ NewPart.Hash = DXContainerYAML::ShaderHash(*Hash);
+ 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 8363700..9df483b 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/YAMLTraits.h"
+#include <optional>
using namespace llvm;
@@ -32,7 +33,7 @@
DenseMap<StringRef, uint32_t> UsedSectionNames;
std::vector<std::string> SectionNames;
- Optional<uint32_t> ShStrTabIndex;
+ std::optional<uint32_t> ShStrTabIndex;
DenseMap<StringRef, uint32_t> UsedSymbolNames;
std::vector<std::string> SymbolNames;
@@ -53,11 +54,11 @@
Expected<std::vector<ELFYAML::ProgramHeader>>
dumpProgramHeaders(ArrayRef<std::unique_ptr<ELFYAML::Chunk>> Sections);
- Optional<DWARFYAML::Data>
+ std::optional<DWARFYAML::Data>
dumpDWARFSections(std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections);
Error dumpSymbols(const Elf_Shdr *Symtab,
- Optional<std::vector<ELFYAML::Symbol>> &Symbols);
+ std::optional<std::vector<ELFYAML::Symbol>> &Symbols);
Error dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
StringRef StrTable, ELFYAML::Symbol &S);
Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>> dumpSections();
@@ -101,7 +102,7 @@
dumpPlaceholderSection(const Elf_Shdr *Shdr);
bool shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr,
- Optional<DWARFYAML::Data> DWARF);
+ std::optional<DWARFYAML::Data> DWARF);
public:
ELFDumper(const object::ELFFile<ELFT> &O, std::unique_ptr<DWARFContext> DCtx);
@@ -182,7 +183,7 @@
template <class ELFT>
bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
const Elf_Shdr &SHdr,
- Optional<DWARFYAML::Data> DWARF) {
+ std::optional<DWARFYAML::Data> DWARF) {
// We only print the SHT_NULL section at index 0 when it
// has at least one non-null field, because yaml2obj
// normally creates the zero section at index 0 implicitly.
@@ -246,8 +247,7 @@
else
ExpectedOffset = sizeof(typename ELFT::Ehdr);
- for (const std::unique_ptr<ELFYAML::Chunk> &C :
- makeArrayRef(V).drop_front()) {
+ for (const std::unique_ptr<ELFYAML::Chunk> &C : ArrayRef(V).drop_front()) {
ELFYAML::Section &Sec = *cast<ELFYAML::Section>(C.get());
const typename ELFT::Shdr &SecHdr = S[Sec.OriginalSecNdx];
@@ -359,7 +359,7 @@
std::vector<ELFYAML::Section *> OriginalOrder;
if (!Chunks.empty())
for (const std::unique_ptr<ELFYAML::Chunk> &C :
- makeArrayRef(Chunks).drop_front())
+ ArrayRef(Chunks).drop_front())
OriginalOrder.push_back(cast<ELFYAML::Section>(C.get()));
// Sometimes the order of sections in the section header table does not match
@@ -401,10 +401,10 @@
}
llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr<ELFYAML::Chunk> &C) {
- if (isa<ELFYAML::SectionHeaderTable>(*C.get()))
+ if (isa<ELFYAML::SectionHeaderTable>(*C))
return false;
- const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
+ const ELFYAML::Section &S = cast<ELFYAML::Section>(*C);
return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);
});
@@ -494,7 +494,7 @@
// It is not possible to have a non-Section chunk, because
// obj2yaml does not create Fill chunks.
for (const std::unique_ptr<ELFYAML::Chunk> &C : Chunks) {
- ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
+ ELFYAML::Section &S = cast<ELFYAML::Section>(*C);
if (isInSegment<ELFT>(S, Sections[S.OriginalSecNdx], Phdr)) {
if (!PH.FirstSec)
PH.FirstSec = S.Name;
@@ -510,7 +510,7 @@
}
template <class ELFT>
-Optional<DWARFYAML::Data> ELFDumper<ELFT>::dumpDWARFSections(
+std::optional<DWARFYAML::Data> ELFDumper<ELFT>::dumpDWARFSections(
std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections) {
DWARFYAML::Data DWARF;
for (std::unique_ptr<ELFYAML::Chunk> &C : Sections) {
@@ -529,13 +529,13 @@
cantFail(std::move(Err));
if (RawSec->Name == ".debug_aranges")
- Err = dumpDebugARanges(*DWARFCtx.get(), DWARF);
+ Err = dumpDebugARanges(*DWARFCtx, DWARF);
else if (RawSec->Name == ".debug_str")
- Err = dumpDebugStrings(*DWARFCtx.get(), DWARF);
+ Err = dumpDebugStrings(*DWARFCtx, DWARF);
else if (RawSec->Name == ".debug_ranges")
- Err = dumpDebugRanges(*DWARFCtx.get(), DWARF);
+ Err = dumpDebugRanges(*DWARFCtx, DWARF);
else if (RawSec->Name == ".debug_addr")
- Err = dumpDebugAddr(*DWARFCtx.get(), DWARF);
+ Err = dumpDebugAddr(*DWARFCtx, DWARF);
else
continue;
@@ -549,7 +549,7 @@
}
if (DWARF.getNonEmptySectionNames().empty())
- return None;
+ return std::nullopt;
return DWARF;
}
@@ -673,7 +673,8 @@
template <class ELFT>
Error ELFDumper<ELFT>::dumpSymbols(
- const Elf_Shdr *Symtab, Optional<std::vector<ELFYAML::Symbol>> &Symbols) {
+ const Elf_Shdr *Symtab,
+ std::optional<std::vector<ELFYAML::Symbol>> &Symbols) {
if (!Symtab)
return Error::success();
@@ -895,7 +896,7 @@
while (Cur && Cur.tell() < Content.size()) {
if (Shdr->sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
Version = Data.getU8(Cur);
- if (Cur && Version > 1)
+ if (Cur && Version > 2)
return createStringError(
errc::invalid_argument,
"invalid SHT_LLVM_BB_ADDR_MAP section version: " +
@@ -906,11 +907,12 @@
uint64_t NumBlocks = Data.getULEB128(Cur);
std::vector<ELFYAML::BBAddrMapEntry::BBEntry> BBEntries;
// Read the specified number of BB entries, or until decoding fails.
- for (uint64_t BlockID = 0; Cur && BlockID < NumBlocks; ++BlockID) {
+ for (uint64_t BlockIndex = 0; Cur && BlockIndex < NumBlocks; ++BlockIndex) {
+ uint32_t ID = Version >= 2 ? Data.getULEB128(Cur) : BlockIndex;
uint64_t Offset = Data.getULEB128(Cur);
uint64_t Size = Data.getULEB128(Cur);
uint64_t Metadata = Data.getULEB128(Cur);
- BBEntries.push_back({Offset, Size, Metadata});
+ BBEntries.push_back({ID, Offset, Size, Metadata});
}
Entries.push_back(
{Version, Feature, Address, /*NumBlocks=*/{}, std::move(BBEntries)});
diff --git a/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp b/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp
index 6b121a74..c96b6cc 100644
--- a/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp
+++ b/src/llvm-project/llvm/tools/obj2yaml/macho2yaml.cpp
@@ -41,6 +41,8 @@
void dumpExportTrie(std::unique_ptr<MachOYAML::Object> &Y);
void dumpSymbols(std::unique_ptr<MachOYAML::Object> &Y);
void dumpIndirectSymbols(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpChainedFixups(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpDataInCode(std::unique_ptr<MachOYAML::Object> &Y);
template <typename SectionType>
Expected<MachOYAML::Section> constructSectionCommon(SectionType Sec,
@@ -190,7 +192,7 @@
if (SecName.startswith("__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.get(), Y.DWARF))
+ if (Error Err = dumpDebugSection(SecName, *DWARFCtx, Y.DWARF))
consumeError(std::move(Err));
else
S->content.reset();
@@ -324,8 +326,7 @@
if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
MachO::swapStruct(LC.Data.load_command_data);
if (Expected<const char *> ExpectedEndPtr =
- processLoadCommandData<MachO::load_command>(LC, LoadCmd,
- *Y.get()))
+ processLoadCommandData<MachO::load_command>(LC, LoadCmd, *Y))
EndPtr = *ExpectedEndPtr;
else
return ExpectedEndPtr.takeError();
@@ -356,6 +357,8 @@
dumpSymbols(Y);
dumpIndirectSymbols(Y);
dumpFunctionStarts(Y);
+ dumpChainedFixups(Y);
+ dumpDataInCode(Y);
}
void MachODumper::dumpFunctionStarts(std::unique_ptr<MachOYAML::Object> &Y) {
@@ -386,7 +389,7 @@
ULEB = decodeULEB128(OpCode + 1, &Count);
RebaseOp.ExtraData.push_back(ULEB);
OpCode += Count;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Intentionally no break here -- This opcode has two ULEB values
case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:
@@ -434,7 +437,7 @@
ULEB = decodeULEB128(OpCode + 1, &Count);
BindOp.ULEBExtraData.push_back(ULEB);
OpCode += Count;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Intentionally no break here -- this opcode has two ULEB values
case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
@@ -576,7 +579,10 @@
void MachODumper::dumpExportTrie(std::unique_ptr<MachOYAML::Object> &Y) {
MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+ // The exports trie can be in LC_DYLD_INFO or LC_DYLD_EXPORTS_TRIE
auto ExportsTrie = Obj.getDyldInfoExportsTrie();
+ if (ExportsTrie.empty())
+ ExportsTrie = Obj.getDyldExportsTrie();
processExportNode(ExportsTrie.begin(), ExportsTrie.end(), LEData.ExportTrie);
}
@@ -620,6 +626,39 @@
LEData.IndirectSymbols.push_back(Obj.getIndirectSymbolTableEntry(DLC, i));
}
+void MachODumper::dumpChainedFixups(std::unique_ptr<MachOYAML::Object> &Y) {
+ MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+
+ for (const auto &LC : Y->LoadCommands) {
+ if (LC.Data.load_command_data.cmd == llvm::MachO::LC_DYLD_CHAINED_FIXUPS) {
+ const MachO::linkedit_data_command &DC =
+ LC.Data.linkedit_data_command_data;
+ if (DC.dataoff) {
+ assert(DC.dataoff < Obj.getData().size());
+ assert(DC.dataoff + DC.datasize <= Obj.getData().size());
+ const char *Bytes = Obj.getData().data() + DC.dataoff;
+ for (size_t Idx = 0; Idx < DC.datasize; Idx++) {
+ LEData.ChainedFixups.push_back(Bytes[Idx]);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void MachODumper::dumpDataInCode(std::unique_ptr<MachOYAML::Object> &Y) {
+ MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+
+ MachO::linkedit_data_command DIC = Obj.getDataInCodeLoadCommand();
+ uint32_t NumEntries = DIC.datasize / sizeof(MachO::data_in_code_entry);
+ for (uint32_t Idx = 0; Idx < NumEntries; ++Idx) {
+ MachO::data_in_code_entry DICE =
+ Obj.getDataInCodeTableEntry(DIC.dataoff, Idx);
+ MachOYAML::DataInCodeEntry Entry{DICE.offset, DICE.length, DICE.kind};
+ LEData.DataInCode.emplace_back(Entry);
+ }
+}
+
Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj,
unsigned RawSegments) {
std::unique_ptr<DWARFContext> DCtx = DWARFContext::create(Obj);
diff --git a/src/llvm-project/llvm/tools/opt/CMakeLists.txt b/src/llvm-project/llvm/tools/opt/CMakeLists.txt
index bbba707..6b2d6b4 100644
--- a/src/llvm-project/llvm/tools/opt/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/opt/CMakeLists.txt
@@ -14,6 +14,7 @@
Extensions
IPO
IRReader
+ IRPrinter
InstCombine
Instrumentation
MC
@@ -22,6 +23,7 @@
ScalarOpts
Support
Target
+ TargetParser
TransformUtils
Vectorize
Passes
@@ -30,9 +32,7 @@
add_llvm_tool(opt
AnalysisWrappers.cpp
BreakpointPrinter.cpp
- GraphPrinters.cpp
NewPMDriver.cpp
- PrintSCC.cpp
opt.cpp
DEPENDS
@@ -40,7 +40,3 @@
SUPPORT_PLUGINS
)
export_executable_symbols_for_plugins(opt)
-
-if(LLVM_BUILD_EXAMPLES)
- target_link_libraries(opt PRIVATE ExampleIRTransforms)
-endif(LLVM_BUILD_EXAMPLES)
diff --git a/src/llvm-project/llvm/tools/opt/GraphPrinters.cpp b/src/llvm-project/llvm/tools/opt/GraphPrinters.cpp
deleted file mode 100644
index 611fb20..0000000
--- a/src/llvm-project/llvm/tools/opt/GraphPrinters.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- GraphPrinters.cpp - DOT printers for various graph types -----------===//
-//
-// 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 several printers for various different types of graphs used
-// by the LLVM infrastructure. It uses the generic graph interface to convert
-// the graph into a .dot graph. These graphs can then be processed with the
-// "dot" tool to convert them to postscript or some other suitable format.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/IR/Dominators.h"
-#include "llvm/Pass.h"
-
-using namespace llvm;
-
-//===----------------------------------------------------------------------===//
-// DomInfoPrinter Pass
-//===----------------------------------------------------------------------===//
-
-namespace {
- class DomInfoPrinter : public FunctionPass {
- public:
- static char ID; // Pass identification, replacement for typeid
- DomInfoPrinter() : FunctionPass(ID) {}
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- AU.addRequired<DominatorTreeWrapperPass>();
- }
-
- bool runOnFunction(Function &F) override {
- getAnalysis<DominatorTreeWrapperPass>().print(dbgs());
- return false;
- }
- };
-}
-
-char DomInfoPrinter::ID = 0;
-static RegisterPass<DomInfoPrinter>
-DIP("print-dom-info", "Dominator Info Printer", true, true);
diff --git a/src/llvm-project/llvm/tools/opt/NewPMDriver.cpp b/src/llvm-project/llvm/tools/opt/NewPMDriver.cpp
index 61d0e12..a8db0c6 100644
--- a/src/llvm-project/llvm/tools/opt/NewPMDriver.cpp
+++ b/src/llvm-project/llvm/tools/opt/NewPMDriver.cpp
@@ -21,16 +21,17 @@
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Dominators.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/IRPrinter/IRPrintingPasses.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
@@ -152,30 +153,66 @@
"the FullLinkTimeOptimizationLast extension point into default "
"pipelines"),
cl::Hidden);
+/// @}}
-// Individual pipeline tuning options.
-extern cl::opt<bool> DisableLoopUnrolling;
+static cl::opt<bool> DisablePipelineVerification(
+ "disable-pipeline-verification",
+ cl::desc("Only has an effect when specified with -print-pipeline-passes. "
+ "Disables verifying that the textual pipeline generated by "
+ "-print-pipeline-passes can be used to create a pipeline."),
+ cl::Hidden);
-namespace llvm {
-extern cl::opt<PGOKind> PGOKindFlag;
-extern cl::opt<std::string> ProfileFile;
-extern cl::opt<CSPGOKind> CSPGOKindFlag;
-extern cl::opt<std::string> CSProfileGenFile;
-extern cl::opt<bool> DisableBasicAA;
-extern cl::opt<bool> PrintPipelinePasses;
-} // namespace llvm
+
+static cl::opt<PGOKind>
+ PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
+ cl::desc("The kind of profile guided optimization"),
+ cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
+ clEnumValN(InstrGen, "pgo-instr-gen-pipeline",
+ "Instrument the IR to generate profile."),
+ clEnumValN(InstrUse, "pgo-instr-use-pipeline",
+ "Use instrumented profile to guide PGO."),
+ clEnumValN(SampleUse, "pgo-sample-use-pipeline",
+ "Use sampled profile to guide PGO.")));
+static cl::opt<std::string> ProfileFile("profile-file",
+ cl::desc("Path to the profile."), cl::Hidden);
+
+static cl::opt<CSPGOKind> CSPGOKindFlag(
+ "cspgo-kind", cl::init(NoCSPGO), cl::Hidden,
+ cl::desc("The kind of context sensitive profile guided optimization"),
+ cl::values(
+ clEnumValN(NoCSPGO, "nocspgo", "Do not use CSPGO."),
+ clEnumValN(
+ CSInstrGen, "cspgo-instr-gen-pipeline",
+ "Instrument (context sensitive) the IR to generate profile."),
+ clEnumValN(
+ CSInstrUse, "cspgo-instr-use-pipeline",
+ "Use instrumented (context sensitive) profile to guide PGO.")));
+
+static cl::opt<std::string> CSProfileGenFile(
+ "cs-profilegen-file",
+ cl::desc("Path to the instrumented context sensitive profile."),
+ cl::Hidden);
static cl::opt<std::string>
ProfileRemappingFile("profile-remapping-file",
cl::desc("Path to the profile remapping file."),
cl::Hidden);
+
static cl::opt<bool> DebugInfoForProfiling(
- "new-pm-debug-info-for-profiling", cl::init(false), cl::Hidden,
+ "debug-info-for-profiling", cl::init(false), cl::Hidden,
cl::desc("Emit special debug info to enable PGO profile generation."));
+
static cl::opt<bool> PseudoProbeForProfiling(
- "new-pm-pseudo-probe-for-profiling", cl::init(false), cl::Hidden,
+ "pseudo-probe-for-profiling", cl::init(false), cl::Hidden,
cl::desc("Emit pseudo probes to enable PGO profile generation."));
-/// @}}
+
+static cl::opt<bool> DisableLoopUnrolling(
+ "disable-loop-unrolling",
+ cl::desc("Disable loop unrolling in all relevant passes"), cl::init(false));
+
+namespace llvm {
+extern cl::opt<bool> PrintPipelinePasses;
+} // namespace llvm
template <typename PassManagerT>
bool tryParsePipelineText(PassBuilder &PB,
@@ -287,7 +324,7 @@
TargetLibraryInfoImpl *TLII, ToolOutputFile *Out,
ToolOutputFile *ThinLTOLinkOut,
ToolOutputFile *OptRemarkFile,
- StringRef PassPipeline, ArrayRef<StringRef> Passes,
+ StringRef PassPipeline,
ArrayRef<PassPlugin> PassPlugins,
OutputKind OK, VerifierKind VK,
bool ShouldPreserveAssemblyUseListOrder,
@@ -296,7 +333,7 @@
bool EnableDebugify, bool VerifyDIPreserve) {
bool VerifyEachPass = VK == VK_VerifyEachPass;
- Optional<PGOOptions> P;
+ std::optional<PGOOptions> P;
switch (PGOKindFlag) {
case InstrGen:
P = PGOOptions(ProfileFile, "", "", PGOOptions::IRInstr);
@@ -313,15 +350,19 @@
P = PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction,
DebugInfoForProfiling, PseudoProbeForProfiling);
else
- P = None;
+ P = std::nullopt;
}
if (CSPGOKindFlag != NoCSPGO) {
if (P && (P->Action == PGOOptions::IRInstr ||
- P->Action == PGOOptions::SampleUse))
+ P->Action == PGOOptions::SampleUse)) {
errs() << "CSPGOKind cannot be used with IRInstr or SampleUse";
+ return false;
+ }
if (CSPGOKindFlag == CSInstrGen) {
- if (CSProfileGenFile.empty())
+ if (CSProfileGenFile.empty()) {
errs() << "CSInstrGen needs to specify CSProfileGenFile";
+ return false;
+ }
if (P) {
P->CSAction = PGOOptions::CSIRInstr;
P->CSProfileGenFile = CSProfileGenFile;
@@ -329,8 +370,10 @@
P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile,
PGOOptions::NoAction, PGOOptions::CSIRInstr);
} else /* CSPGOKindFlag == CSInstrUse */ {
- if (!P)
+ if (!P) {
errs() << "CSInstrUse needs to be together with InstrUse";
+ return false;
+ }
P->CSAction = PGOOptions::CSIRUse;
}
}
@@ -346,8 +389,8 @@
PrintPassOptions PrintPassOpts;
PrintPassOpts.Verbose = DebugPM == DebugLogging::Verbose;
PrintPassOpts.SkipAnalyses = DebugPM == DebugLogging::Quiet;
- StandardInstrumentations SI(DebugPM != DebugLogging::None, VerifyEachPass,
- PrintPassOpts);
+ StandardInstrumentations SI(M.getContext(), DebugPM != DebugLogging::None,
+ VerifyEachPass, PrintPassOpts);
SI.registerCallbacks(PIC, &FAM);
DebugifyEachInstrumentation Debugify;
DebugifyStatsMap DIStatsMap;
@@ -376,17 +419,6 @@
for (auto &PassPlugin : PassPlugins)
PassPlugin.registerPassBuilderCallbacks(PB);
- PB.registerPipelineParsingCallback(
- [](StringRef Name, ModulePassManager &MPM,
- ArrayRef<PassBuilder::PipelineElement>) {
- AddressSanitizerOptions Opts;
- if (Name == "asan-pipeline") {
- MPM.addPass(ModuleAddressSanitizerPass(Opts));
- return true;
- }
- return false;
- });
-
#define HANDLE_EXTENSION(Ext) \
get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);
#include "llvm/Support/Extension.def"
@@ -394,34 +426,9 @@
// Specially handle the alias analysis manager so that we can register
// a custom pipeline of AA passes with it.
AAManager AA;
- if (Passes.empty()) {
- if (auto Err = PB.parseAAPipeline(AA, AAPipeline)) {
- errs() << Arg0 << ": " << toString(std::move(Err)) << "\n";
- return false;
- }
- }
-
- // For compatibility with the legacy PM AA pipeline.
- // AAResultsWrapperPass by default provides basic-aa in the legacy PM
- // unless -disable-basic-aa is specified.
- // TODO: remove this once tests implicitly requiring basic-aa use -passes= and
- // -aa-pipeline=basic-aa.
- if (!Passes.empty() && !DisableBasicAA) {
- if (auto Err = PB.parseAAPipeline(AA, "basic-aa")) {
- errs() << Arg0 << ": " << toString(std::move(Err)) << "\n";
- return false;
- }
- }
-
- // For compatibility with legacy pass manager.
- // Alias analyses are not specially specified when using the legacy PM.
- for (auto PassName : Passes) {
- if (PB.isAAPassName(PassName)) {
- if (auto Err = PB.parseAAPipeline(AA, PassName)) {
- errs() << Arg0 << ": " << toString(std::move(Err)) << "\n";
- return false;
- }
- }
+ if (auto Err = PB.parseAAPipeline(AA, AAPipeline)) {
+ errs() << Arg0 << ": " << toString(std::move(Err)) << "\n";
+ return false;
}
// Register the AA manager first so that our version is the one used.
@@ -437,8 +444,6 @@
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
ModulePassManager MPM;
- if (VK > VK_NoVerifier)
- MPM.addPass(VerifierPass());
if (EnableDebugify)
MPM.addPass(NewPMDebugifyPass());
if (VerifyDIPreserve)
@@ -447,38 +452,11 @@
// Add passes according to the -passes options.
if (!PassPipeline.empty()) {
- assert(Passes.empty() &&
- "PassPipeline and Passes should not both contain passes");
if (auto Err = PB.parsePassPipeline(MPM, PassPipeline)) {
errs() << Arg0 << ": " << toString(std::move(Err)) << "\n";
return false;
}
}
- // Add passes specified using the legacy PM syntax (i.e. not using
- // -passes). This should be removed later when such support has been
- // deprecated, i.e. when all lit tests running opt (and not using
- // -enable-new-pm=0) have been updated to use -passes.
- for (auto PassName : Passes) {
- std::string ModifiedPassName(PassName.begin(), PassName.end());
- if (PB.isAnalysisPassName(PassName))
- ModifiedPassName = "require<" + ModifiedPassName + ">";
- // FIXME: These translations are supposed to be removed when lit tests that
- // use these names have been updated to use the -passes syntax (and when the
- // support for using the old syntax to specify passes is considered as
- // deprecated for the new PM).
- if (ModifiedPassName == "early-cse-memssa")
- ModifiedPassName = "early-cse<memssa>";
- else if (ModifiedPassName == "post-inline-ee-instrument")
- ModifiedPassName = "ee-instrument<post-inline>";
- else if (ModifiedPassName == "loop-extract-single")
- ModifiedPassName = "loop-extract<single>";
- else if (ModifiedPassName == "lower-matrix-intrinsics-minimal")
- ModifiedPassName = "lower-matrix-intrinsics<minimal>";
- if (auto Err = PB.parsePassPipeline(MPM, ModifiedPassName)) {
- errs() << Arg0 << ": " << toString(std::move(Err)) << "\n";
- return false;
- }
- }
if (VK > VK_NoVerifier)
MPM.addPass(VerifierPass());
@@ -486,16 +464,16 @@
MPM.addPass(NewPMCheckDebugifyPass(false, "", &DIStatsMap));
if (VerifyDIPreserve)
MPM.addPass(NewPMCheckDebugifyPass(
- false, "", nullptr, DebugifyMode::OriginalDebugInfo, &DebugInfoBeforePass,
- VerifyDIPreserveExport));
+ false, "", nullptr, DebugifyMode::OriginalDebugInfo,
+ &DebugInfoBeforePass, VerifyDIPreserveExport));
// Add any relevant output pass at the end of the pipeline.
switch (OK) {
case OK_NoOutput:
break; // No output pass needed.
case OK_OutputAssembly:
- MPM.addPass(
- PrintModulePass(Out->os(), "", ShouldPreserveAssemblyUseListOrder));
+ MPM.addPass(PrintModulePass(
+ Out->os(), "", ShouldPreserveAssemblyUseListOrder, EmitSummaryIndex));
break;
case OK_OutputBitcode:
MPM.addPass(BitcodeWriterPass(Out->os(), ShouldPreserveBitcodeUseListOrder,
@@ -513,11 +491,26 @@
// Print a textual, '-passes=' compatible, representation of pipeline if
// requested.
if (PrintPipelinePasses) {
- MPM.printPipeline(outs(), [&PIC](StringRef ClassName) {
+ std::string Pipeline;
+ raw_string_ostream SOS(Pipeline);
+ MPM.printPipeline(SOS, [&PIC](StringRef ClassName) {
auto PassName = PIC.getPassNameForClassName(ClassName);
return PassName.empty() ? ClassName : PassName;
});
+ outs() << Pipeline;
outs() << "\n";
+
+ if (!DisablePipelineVerification) {
+ // Check that we can parse the returned pipeline string as an actual
+ // pipeline.
+ ModulePassManager TempPM;
+ if (auto Err = PB.parsePassPipeline(TempPM, Pipeline)) {
+ errs() << "Could not parse dumped pass pipeline: "
+ << toString(std::move(Err)) << "\n";
+ return false;
+ }
+ }
+
return true;
}
diff --git a/src/llvm-project/llvm/tools/opt/NewPMDriver.h b/src/llvm-project/llvm/tools/opt/NewPMDriver.h
index 543f91c..a3cdd15 100644
--- a/src/llvm-project/llvm/tools/opt/NewPMDriver.h
+++ b/src/llvm-project/llvm/tools/opt/NewPMDriver.h
@@ -43,11 +43,7 @@
OK_OutputBitcode,
OK_OutputThinLTOBitcode,
};
-enum VerifierKind {
- VK_NoVerifier,
- VK_VerifyInAndOut,
- VK_VerifyEachPass
-};
+enum VerifierKind { VK_NoVerifier, VK_VerifyOut, VK_VerifyEachPass };
enum PGOKind {
NoPGO,
InstrGen,
@@ -71,7 +67,7 @@
bool runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
TargetLibraryInfoImpl *TLII, ToolOutputFile *Out,
ToolOutputFile *ThinLinkOut, ToolOutputFile *OptRemarkFile,
- StringRef PassPipeline, ArrayRef<StringRef> PassInfos,
+ StringRef PassPipeline,
ArrayRef<PassPlugin> PassPlugins, opt_tool::OutputKind OK,
opt_tool::VerifierKind VK,
bool ShouldPreserveAssemblyUseListOrder,
diff --git a/src/llvm-project/llvm/tools/opt/PrintSCC.cpp b/src/llvm-project/llvm/tools/opt/PrintSCC.cpp
deleted file mode 100644
index 1ca5274..0000000
--- a/src/llvm-project/llvm/tools/opt/PrintSCC.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-//===- PrintSCC.cpp - Enumerate SCCs in some key graphs -------------------===//
-//
-// 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 provides passes to print out SCCs in a CFG or a CallGraph.
-// Normally, you would not use these passes; instead, you would use the
-// scc_iterator directly to enumerate SCCs and process them in some way. These
-// passes serve three purposes:
-//
-// (1) As a reference for how to use the scc_iterator.
-// (2) To print out the SCCs for a CFG or a CallGraph:
-// analyze -print-cfg-sccs to print the SCCs in each CFG of a module.
-// analyze -print-cfg-sccs -stats to print the #SCCs and the maximum SCC size.
-// analyze -print-cfg-sccs -debug > /dev/null to watch the algorithm in action.
-//
-// and similarly:
-// analyze -print-callgraph-sccs [-stats] [-debug] to print SCCs in the CallGraph
-//
-// (3) To test the scc_iterator.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/SCCIterator.h"
-#include "llvm/Analysis/CallGraph.h"
-#include "llvm/IR/CFG.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
-
-namespace {
- struct CFGSCC : public FunctionPass {
- static char ID; // Pass identification, replacement for typeid
- CFGSCC() : FunctionPass(ID) {}
- bool runOnFunction(Function& func) override;
-
- void print(raw_ostream &O, const Module* = nullptr) const override { }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- }
- };
-
- struct CallGraphSCC : public ModulePass {
- static char ID; // Pass identification, replacement for typeid
- CallGraphSCC() : ModulePass(ID) {}
-
- // run - Print out SCCs in the call graph for the specified module.
- bool runOnModule(Module &M) override;
-
- void print(raw_ostream &O, const Module* = nullptr) const override { }
-
- // getAnalysisUsage - This pass requires the CallGraph.
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- AU.addRequired<CallGraphWrapperPass>();
- }
- };
-}
-
-char CFGSCC::ID = 0;
-static RegisterPass<CFGSCC>
-Y("print-cfg-sccs", "Print SCCs of each function CFG");
-
-char CallGraphSCC::ID = 0;
-static RegisterPass<CallGraphSCC>
-Z("print-callgraph-sccs", "Print SCCs of the Call Graph");
-
-bool CFGSCC::runOnFunction(Function &F) {
- unsigned sccNum = 0;
- errs() << "SCCs for Function " << F.getName() << " in PostOrder:";
- for (scc_iterator<Function*> SCCI = scc_begin(&F); !SCCI.isAtEnd(); ++SCCI) {
- const std::vector<BasicBlock *> &nextSCC = *SCCI;
- errs() << "\nSCC #" << ++sccNum << " : ";
- for (BasicBlock *BB : nextSCC) {
- BB->printAsOperand(errs(), false);
- errs() << ", ";
- }
- if (nextSCC.size() == 1 && SCCI.hasCycle())
- errs() << " (Has self-loop).";
- }
- errs() << "\n";
-
- return true;
-}
-
-
-// run - Print out SCCs in the call graph for the specified module.
-bool CallGraphSCC::runOnModule(Module &M) {
- CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
- unsigned sccNum = 0;
- errs() << "SCCs for the program in PostOrder:";
- for (scc_iterator<CallGraph*> SCCI = scc_begin(&CG); !SCCI.isAtEnd();
- ++SCCI) {
- const std::vector<CallGraphNode*> &nextSCC = *SCCI;
- errs() << "\nSCC #" << ++sccNum << " : ";
- for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(),
- E = nextSCC.end(); I != E; ++I)
- errs() << ((*I)->getFunction() ? (*I)->getFunction()->getName()
- : "external node") << ", ";
- if (nextSCC.size() == 1 && SCCI.hasCycle())
- errs() << " (Has self-loop).";
- }
- errs() << "\n";
-
- return true;
-}
diff --git a/src/llvm-project/llvm/tools/opt/opt.cpp b/src/llvm-project/llvm/tools/opt/opt.cpp
index a02997f..40632b4 100644
--- a/src/llvm-project/llvm/tools/opt/opt.cpp
+++ b/src/llvm-project/llvm/tools/opt/opt.cpp
@@ -52,13 +52,12 @@
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Transforms/IPO/AlwaysInliner.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/IPO/WholeProgramDevirt.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Debugify.h"
#include <algorithm>
#include <memory>
+#include <optional>
using namespace llvm;
using namespace opt_tool;
@@ -85,6 +84,8 @@
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> PrintPasses("print-passes",
cl::desc("Print available passes that can be "
@@ -177,10 +178,6 @@
static cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
-cl::opt<bool> DisableLoopUnrolling(
- "disable-loop-unrolling",
- cl::desc("Disable loop unrolling in all relevant passes"), cl::init(false));
-
static cl::opt<bool> EmitSummaryIndex("module-summary",
cl::desc("Emit module summary index"),
cl::init(false));
@@ -254,12 +251,12 @@
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
-static cl::opt<Optional<uint64_t>, false, remarks::HotnessThresholdParser>
+static cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
RemarksHotnessThreshold(
"pass-remarks-hotness-threshold",
cl::desc("Minimum profile count required for "
"an optimization remark to be output. "
- "Use 'auto' to apply the threshold from profile summary."),
+ "Use 'auto' to apply the threshold from profile summary"),
cl::value_desc("N or 'auto'"), cl::init(0), cl::Hidden);
static cl::opt<std::string>
@@ -282,37 +279,6 @@
PassPlugins("load-pass-plugin",
cl::desc("Load passes from plugin library"));
-namespace llvm {
-cl::opt<PGOKind>
- PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
- cl::desc("The kind of profile guided optimization"),
- cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
- clEnumValN(InstrGen, "pgo-instr-gen-pipeline",
- "Instrument the IR to generate profile."),
- clEnumValN(InstrUse, "pgo-instr-use-pipeline",
- "Use instrumented profile to guide PGO."),
- clEnumValN(SampleUse, "pgo-sample-use-pipeline",
- "Use sampled profile to guide PGO.")));
-cl::opt<std::string> ProfileFile("profile-file",
- cl::desc("Path to the profile."), cl::Hidden);
-
-cl::opt<CSPGOKind> CSPGOKindFlag(
- "cspgo-kind", cl::init(NoCSPGO), cl::Hidden,
- cl::desc("The kind of context sensitive profile guided optimization"),
- cl::values(
- clEnumValN(NoCSPGO, "nocspgo", "Do not use CSPGO."),
- clEnumValN(
- CSInstrGen, "cspgo-instr-gen-pipeline",
- "Instrument (context sensitive) the IR to generate profile."),
- clEnumValN(
- CSInstrUse, "cspgo-instr-use-pipeline",
- "Use instrumented (context sensitive) profile to guide PGO.")));
-cl::opt<std::string> CSProfileGenFile(
- "cs-profilegen-file",
- cl::desc("Path to the instrumented context sensitive profile."),
- cl::Hidden);
-} // namespace llvm
-
static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
// Add the pass to the pass manager...
PM.add(P);
@@ -322,54 +288,12 @@
PM.add(createVerifierPass());
}
-/// This routine adds optimization passes based on selected optimization level,
-/// OptLevel.
-///
-/// OptLevel - Optimization Level
-static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
- legacy::FunctionPassManager &FPM,
- TargetMachine *TM, unsigned OptLevel,
- unsigned SizeLevel) {
- if (!NoVerify || VerifyEach)
- FPM.add(createVerifierPass()); // Verify that input is correct
-
- PassManagerBuilder Builder;
- Builder.OptLevel = OptLevel;
- Builder.SizeLevel = SizeLevel;
-
- if (OptLevel > 1) {
- Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
- } else {
- Builder.Inliner = createAlwaysInlinerLegacyPass();
- }
- Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ?
- DisableLoopUnrolling : OptLevel == 0;
-
- Builder.LoopVectorize = OptLevel > 1 && SizeLevel < 2;
-
- Builder.SLPVectorize = OptLevel > 1 && SizeLevel < 2;
-
- if (TM)
- TM->adjustPassManager(Builder);
-
- Builder.populateFunctionPassManager(FPM);
- Builder.populateModulePassManager(MPM);
-}
-
//===----------------------------------------------------------------------===//
// CodeGen-related helper functions.
//
static CodeGenOpt::Level GetCodeGenOptLevel() {
- if (CodeGenOptLevel.getNumOccurrences())
- return static_cast<CodeGenOpt::Level>(unsigned(CodeGenOptLevel));
- if (OptLevelO1)
- return CodeGenOpt::Less;
- if (OptLevelO2)
- return CodeGenOpt::Default;
- if (OptLevelO3)
- return CodeGenOpt::Aggressive;
- return CodeGenOpt::None;
+ return static_cast<CodeGenOpt::Level>(unsigned(CodeGenOptLevel));
}
// Returns the TargetMachine instance or zero if no triple is provided.
@@ -390,10 +314,6 @@
codegen::getExplicitCodeModel(), GetCodeGenOptLevel());
}
-#ifdef BUILD_EXAMPLES
-void initializeExampleIRTransforms(llvm::PassRegistry &Registry);
-#endif
-
struct TimeTracerRAII {
TimeTracerRAII(StringRef ProgramName) {
if (TimeTrace)
@@ -440,22 +360,41 @@
"amdgcn-", "polly-", "riscv-", "dxil-"};
std::vector<StringRef> PassNameContain = {"ehprepare"};
std::vector<StringRef> PassNameExact = {
- "safe-stack", "cost-model",
- "codegenprepare", "interleaved-load-combine",
- "unreachableblockelim", "verify-safepoint-ir",
- "atomic-expand", "expandvp",
- "hardware-loops", "type-promotion",
- "mve-tail-predication", "interleaved-access",
- "global-merge", "pre-isel-intrinsic-lowering",
- "expand-reductions", "indirectbr-expand",
- "generic-to-nvvm", "expandmemcmp",
- "loop-reduce", "lower-amx-type",
- "pre-amx-config", "lower-amx-intrinsics",
- "polyhedral-info", "print-polyhedral-info",
- "replace-with-veclib", "jmc-instrument",
- "dot-regions", "dot-regions-only",
- "view-regions", "view-regions-only",
- "select-optimize"};
+ "safe-stack",
+ "cost-model",
+ "codegenprepare",
+ "interleaved-load-combine",
+ "unreachableblockelim",
+ "verify-safepoint-ir",
+ "atomic-expand",
+ "expandvp",
+ "hardware-loops",
+ "mve-tail-predication",
+ "interleaved-access",
+ "global-merge",
+ "pre-isel-intrinsic-lowering",
+ "expand-reductions",
+ "indirectbr-expand",
+ "generic-to-nvvm",
+ "expandmemcmp",
+ "loop-reduce",
+ "lower-amx-type",
+ "pre-amx-config",
+ "lower-amx-intrinsics",
+ "polyhedral-info",
+ "print-polyhedral-info",
+ "replace-with-veclib",
+ "jmc-instrument",
+ "dot-regions",
+ "dot-regions-only",
+ "view-regions",
+ "view-regions-only",
+ "select-optimize",
+ "expand-large-div-rem",
+ "structurizecfg",
+ "fix-irreducible",
+ "expand-large-fp-convert"
+ };
for (const auto &P : PassNamePrefix)
if (Pass.startswith(P))
return true;
@@ -493,17 +432,16 @@
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
- initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
- initializeAggressiveInstCombine(Registry);
- initializeInstrumentation(Registry);
initializeTarget(Registry);
// For codegen passes, only passes that do IR to IR transformation are
// supported.
+ initializeExpandLargeDivRemLegacyPassPass(Registry);
+ initializeExpandLargeFpConvertLegacyPassPass(Registry);
initializeExpandMemCmpPassPass(Registry);
initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry);
initializeSelectOptimizePass(Registry);
@@ -525,14 +463,9 @@
initializeWasmEHPreparePass(Registry);
initializeWriteBitcodePassPass(Registry);
initializeHardwareLoopsPass(Registry);
- initializeTypePromotionPass(Registry);
initializeReplaceWithVeclibLegacyPass(Registry);
initializeJMCInstrumenterPass(Registry);
-#ifdef BUILD_EXAMPLES
- initializeExampleIRTransforms(Registry);
-#endif
-
SmallVector<PassPlugin, 1> PluginList;
PassPlugins.setCallback([&](const std::string &PluginPath) {
auto Plugin = PassPlugin::Load(PluginPath);
@@ -544,6 +477,9 @@
PluginList.emplace_back(Plugin.get());
});
+ // Register the Target and CPU printer for --version.
+ cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);
+
cl::ParseCommandLineOptions(argc, argv,
"llvm .bc -> .bc modular optimizer and analysis printer\n");
@@ -556,6 +492,15 @@
const bool UseNPM = (EnableNewPassManager && !shouldForceLegacyPM()) ||
PassPipeline.getNumOccurrences() > 0;
+ if (UseNPM && !PassList.empty()) {
+ errs() << "The `opt -passname` syntax for the new pass manager is "
+ "not supported, please use `opt -passes=<pipeline>` (or the `-p` "
+ "alias for a more concise version).\n";
+ errs() << "See https://llvm.org/docs/NewPassManager.html#invoking-opt "
+ "for more details on the pass pipeline syntax.\n\n";
+ return 1;
+ }
+
if (!UseNPM && PluginList.size()) {
errs() << argv[0] << ": " << PassPlugins.ArgStr
<< " specified with legacy PM.\n";
@@ -589,9 +534,9 @@
std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
// Load the input module...
- auto SetDataLayout = [](StringRef) -> Optional<std::string> {
+ auto SetDataLayout = [](StringRef, StringRef) -> std::optional<std::string> {
if (ClDataLayout.empty())
- return None;
+ return std::nullopt;
return ClDataLayout;
};
std::unique_ptr<Module> M;
@@ -600,7 +545,8 @@
InputFilename, Err, Context, nullptr, SetDataLayout)
.Mod;
else
- M = parseIRFile(InputFilename, Err, Context, SetDataLayout);
+ M = parseIRFile(InputFilename, Err, Context,
+ ParserCallbacks(SetDataLayout));
if (!M) {
Err.print(argv[0], errs());
@@ -730,26 +676,19 @@
"-debug-pass-manager, or use the legacy PM (-enable-new-pm=0)\n";
return 1;
}
- if (PassPipeline.getNumOccurrences() > 0 && PassList.size() > 0) {
- errs()
- << "Cannot specify passes via both -foo-pass and --passes=foo-pass\n";
- return 1;
- }
auto NumOLevel = OptLevelO0 + OptLevelO1 + OptLevelO2 + OptLevelO3 +
OptLevelOs + OptLevelOz;
if (NumOLevel > 1) {
errs() << "Cannot specify multiple -O#\n";
return 1;
}
- if (NumOLevel > 0 &&
- (PassPipeline.getNumOccurrences() > 0 || PassList.size() > 0)) {
+ if (NumOLevel > 0 && (PassPipeline.getNumOccurrences() > 0)) {
errs() << "Cannot specify -O# and --passes=/--foo-pass, use "
"-passes='default<O#>,other-pass'\n";
return 1;
}
std::string Pipeline = PassPipeline;
- SmallVector<StringRef, 4> Passes;
if (OptLevelO0)
Pipeline = "default<O0>";
if (OptLevelO1)
@@ -762,15 +701,13 @@
Pipeline = "default<Os>";
if (OptLevelOz)
Pipeline = "default<Oz>";
- for (const auto &P : PassList)
- Passes.push_back(P->getPassArgument());
OutputKind OK = OK_NoOutput;
if (!NoOutput)
OK = OutputAssembly
? OK_OutputAssembly
: (OutputThinLTOBC ? OK_OutputThinLTOBitcode : OK_OutputBitcode);
- VerifierKind VK = VK_VerifyInAndOut;
+ VerifierKind VK = VK_VerifyOut;
if (NoVerify)
VK = VK_NoVerifier;
else if (VerifyEach)
@@ -781,7 +718,7 @@
// layer.
return runPassPipeline(argv[0], *M, TM.get(), &TLII, Out.get(),
ThinLinkOut.get(), RemarksFile.get(), Pipeline,
- Passes, PluginList, OK, VK, PreserveAssemblyUseListOrder,
+ PluginList, OK, VK, PreserveAssemblyUseListOrder,
PreserveBitcodeUseListOrder, EmitSummaryIndex,
EmitModuleHash, EnableDebugify,
VerifyDebugInfoPreserve)
@@ -789,6 +726,23 @@
: 1;
}
+ if (OptLevelO0 || OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz ||
+ OptLevelO3) {
+ errs() << "Cannot use -O# with legacy PM.\n";
+ return 1;
+ }
+ if (EmitSummaryIndex) {
+ errs() << "Cannot use -module-summary with legacy PM.\n";
+ return 1;
+ }
+ if (EmitModuleHash) {
+ errs() << "Cannot use -module-hash with legacy PM.\n";
+ return 1;
+ }
+ if (OutputThinLTOBC) {
+ errs() << "Cannot use -thinlto-bc with legacy PM.\n";
+ return 1;
+ }
// Create a PassManager to hold and optimize the collection of passes we are
// about to build. If the -debugify-each option is set, wrap each pass with
// the (-check)-debugify passes.
@@ -828,12 +782,6 @@
}
std::unique_ptr<legacy::FunctionPassManager> FPasses;
- if (OptLevelO0 || OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz ||
- OptLevelO3) {
- FPasses.reset(new legacy::FunctionPassManager(M.get()));
- FPasses->add(createTargetTransformInfoWrapperPass(
- TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis()));
- }
if (PrintBreakpoints) {
// Default to standard output.
@@ -862,36 +810,6 @@
// Create a new optimization pass for each one specified on the command line
for (unsigned i = 0; i < PassList.size(); ++i) {
- if (OptLevelO0 && OptLevelO0.getPosition() < PassList.getPosition(i)) {
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 0, 0);
- OptLevelO0 = false;
- }
-
- if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) {
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 1, 0);
- OptLevelO1 = false;
- }
-
- if (OptLevelO2 && OptLevelO2.getPosition() < PassList.getPosition(i)) {
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 0);
- OptLevelO2 = false;
- }
-
- if (OptLevelOs && OptLevelOs.getPosition() < PassList.getPosition(i)) {
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 1);
- OptLevelOs = false;
- }
-
- if (OptLevelOz && OptLevelOz.getPosition() < PassList.getPosition(i)) {
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 2);
- OptLevelOz = false;
- }
-
- if (OptLevelO3 && OptLevelO3.getPosition() < PassList.getPosition(i)) {
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 3, 0);
- OptLevelO3 = false;
- }
-
const PassInfo *PassInf = PassList[i];
Pass *P = nullptr;
if (PassInf->getNormalCtor())
@@ -903,24 +821,6 @@
addPass(Passes, P);
}
- if (OptLevelO0)
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 0, 0);
-
- if (OptLevelO1)
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 1, 0);
-
- if (OptLevelO2)
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 0);
-
- if (OptLevelOs)
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 1);
-
- if (OptLevelOz)
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 2);
-
- if (OptLevelO3)
- AddOptimizationPasses(Passes, *FPasses, TM.get(), 3, 0);
-
if (FPasses) {
FPasses->doInitialization();
for (Function &F : *M)
@@ -963,18 +863,10 @@
BOS = std::make_unique<raw_svector_ostream>(Buffer);
OS = BOS.get();
}
- if (OutputAssembly) {
- if (EmitSummaryIndex)
- report_fatal_error("Text output is incompatible with -module-summary");
- if (EmitModuleHash)
- report_fatal_error("Text output is incompatible with -module-hash");
+ if (OutputAssembly)
Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder));
- } else if (OutputThinLTOBC)
- Passes.add(createWriteThinLTOBitcodePass(
- *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr));
else
- Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder,
- EmitSummaryIndex, EmitModuleHash));
+ Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder));
}
// Before executing passes, print the final values of the LLVM options.
diff --git a/src/llvm-project/llvm/tools/remarks-shlib/CMakeLists.txt b/src/llvm-project/llvm/tools/remarks-shlib/CMakeLists.txt
index f22cedd..bc4bd67 100644
--- a/src/llvm-project/llvm/tools/remarks-shlib/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/remarks-shlib/CMakeLists.txt
@@ -9,7 +9,9 @@
libremarks.cpp
)
- set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Remarks.exports)
+ if (NOT (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB))
+ set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Remarks.exports)
+ endif()
add_llvm_library(Remarks SHARED INSTALL_WITH_TOOLCHAIN ${SOURCES})
diff --git a/src/llvm-project/llvm/tools/sancov/CMakeLists.txt b/src/llvm-project/llvm/tools/sancov/CMakeLists.txt
index 51d8db6..e273195 100644
--- a/src/llvm-project/llvm/tools/sancov/CMakeLists.txt
+++ b/src/llvm-project/llvm/tools/sancov/CMakeLists.txt
@@ -8,6 +8,7 @@
MCDisassembler
Object
Support
+ TargetParser
Symbolize
)
diff --git a/src/llvm-project/llvm/tools/sancov/sancov.cpp b/src/llvm-project/llvm/tools/sancov/sancov.cpp
index e7c985c..9d29e9a 100644
--- a/src/llvm-project/llvm/tools/sancov/sancov.cpp
+++ b/src/llvm-project/llvm/tools/sancov/sancov.cpp
@@ -114,15 +114,6 @@
cl::desc("Ignorelist file (sanitizer ignorelist format)"),
cl::cat(Cat));
-static cl::opt<std::string>
- ClBlacklist("blacklist", cl::init(""), cl::Hidden,
- cl::desc("ignorelist file (sanitizer ignorelist format)"),
- cl::cat(Cat));
-
-static cl::opt<bool> ClUseDefaultBlacklist(
- "use_default_blacklist", cl::init(true), cl::Hidden,
- cl::desc("Controls if default ignorelist should be used"), 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));
@@ -514,7 +505,7 @@
private:
static std::unique_ptr<SpecialCaseList> createDefaultIgnorelist() {
- if ((!ClUseDefaultIgnorelist) && (!ClUseDefaultBlacklist))
+ if (!ClUseDefaultIgnorelist)
return std::unique_ptr<SpecialCaseList>();
std::unique_ptr<MemoryBuffer> MB =
MemoryBuffer::getMemBuffer(DefaultIgnorelistStr);
@@ -525,13 +516,8 @@
}
static std::unique_ptr<SpecialCaseList> createUserIgnorelist() {
- if ((ClBlacklist.empty()) && ClIgnorelist.empty())
+ if (ClIgnorelist.empty())
return std::unique_ptr<SpecialCaseList>();
-
- if (!ClBlacklist.empty())
- return SpecialCaseList::createOrDie({{ClBlacklist}},
- *vfs::getRealFileSystem());
-
return SpecialCaseList::createOrDie({{ClIgnorelist}},
*vfs::getRealFileSystem());
}
diff --git a/src/llvm-project/llvm/tools/split-file/.clang-tidy b/src/llvm-project/llvm/tools/split-file/.clang-tidy
deleted file mode 100644
index acd9361..0000000
--- a/src/llvm-project/llvm/tools/split-file/.clang-tidy
+++ /dev/null
@@ -1,8 +0,0 @@
-InheritParentConfig: true
-CheckOptions:
- - key: readability-identifier-naming.MemberCase
- value: camelBack
- - key: readability-identifier-naming.ParameterCase
- value: camelBack
- - key: readability-identifier-naming.VariableCase
- value: camelBack
diff --git a/src/llvm-project/llvm/tools/split-file/CMakeLists.txt b/src/llvm-project/llvm/tools/split-file/CMakeLists.txt
deleted file mode 100644
index ba99848..0000000
--- a/src/llvm-project/llvm/tools/split-file/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(LLVM_LINK_COMPONENTS
- Support
- )
-
-add_llvm_tool(split-file
- split-file.cpp
- )
diff --git a/src/llvm-project/llvm/tools/split-file/split-file.cpp b/src/llvm-project/llvm/tools/split-file/split-file.cpp
deleted file mode 100644
index 4a92c1b..0000000
--- a/src/llvm-project/llvm/tools/split-file/split-file.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-//===- split-file.cpp - Input splitting utility ---------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Split input into multipe parts separated by regex '^(.|//)--- ' and extract
-// the specified part.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/LineIterator.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
-#include <string>
-#include <system_error>
-
-using namespace llvm;
-
-static cl::OptionCategory cat("split-file Options");
-
-static cl::opt<std::string> input(cl::Positional, cl::desc("filename"),
- cl::cat(cat));
-
-static cl::opt<std::string> output(cl::Positional, cl::desc("directory"),
- cl::value_desc("directory"), cl::cat(cat));
-
-static cl::opt<bool> leadingLines("leading-lines",
- cl::desc("Preserve line numbers"),
- cl::cat(cat));
-
-static cl::opt<bool> noLeadingLines("no-leading-lines",
- cl::desc("Don't preserve line numbers (default)"),
- cl::cat(cat));
-
-static StringRef toolName;
-static int errorCount;
-
-[[noreturn]] static void fatal(StringRef filename, const Twine &message) {
- if (filename.empty())
- WithColor::error(errs(), toolName) << message << '\n';
- else
- WithColor::error(errs(), toolName) << filename << ": " << message << '\n';
- exit(1);
-}
-
-static void error(StringRef filename, int64_t line, const Twine &message) {
- ++errorCount;
- errs() << filename << ':' << line << ": ";
- WithColor::error(errs()) << message << '\n';
-}
-
-namespace {
-struct Part {
- const char *begin = nullptr;
- const char *end = nullptr;
- int64_t leadingLines = 0;
-};
-} // namespace
-
-static int handle(MemoryBuffer &inputBuf, StringRef input) {
- DenseMap<StringRef, Part> partToBegin;
- StringRef lastPart, separator;
- StringRef EOL = inputBuf.getBuffer().detectEOL();
- for (line_iterator i(inputBuf, /*SkipBlanks=*/false, '\0'); !i.is_at_eof();) {
- const int64_t lineNo = i.line_number();
- const StringRef line = *i++;
- const size_t markerLen = line.startswith("//") ? 6 : 5;
- if (!(line.size() >= markerLen &&
- line.substr(markerLen - 4).startswith("--- ")))
- continue;
- separator = line.substr(0, markerLen);
- const StringRef partName = line.substr(markerLen);
- if (partName.empty()) {
- error(input, lineNo, "empty part name");
- continue;
- }
- if (isSpace(partName.front()) || isSpace(partName.back())) {
- error(input, lineNo, "part name cannot have leading or trailing space");
- continue;
- }
-
- auto res = partToBegin.try_emplace(partName);
- if (!res.second) {
- error(input, lineNo,
- "'" + separator + partName + "' occurs more than once");
- continue;
- }
- if (!lastPart.empty())
- partToBegin[lastPart].end = line.data();
- Part &cur = res.first->second;
- if (!i.is_at_eof())
- cur.begin = i->data();
- // If --leading-lines is specified, numEmptyLines is 0. Append newlines so
- // that the extracted part preserves line numbers.
- cur.leadingLines = leadingLines ? i.line_number() - 1 : 0;
-
- lastPart = partName;
- }
- if (lastPart.empty())
- fatal(input, "no part separator was found");
- if (errorCount)
- return 1;
- partToBegin[lastPart].end = inputBuf.getBufferEnd();
-
- std::vector<std::unique_ptr<ToolOutputFile>> outputFiles;
- SmallString<256> partPath;
- for (auto &keyValue : partToBegin) {
- partPath.clear();
- sys::path::append(partPath, output, keyValue.first);
- std::error_code ec =
- sys::fs::create_directories(sys::path::parent_path(partPath));
- if (ec)
- fatal(input, ec.message());
- auto f = std::make_unique<ToolOutputFile>(partPath.str(), ec,
- llvm::sys::fs::OF_None);
- if (!f)
- fatal(input, ec.message());
-
- Part &part = keyValue.second;
- for (int64_t i = 0; i != part.leadingLines; ++i)
- (*f).os() << EOL;
- if (part.begin)
- (*f).os().write(part.begin, part.end - part.begin);
- outputFiles.push_back(std::move(f));
- }
-
- for (std::unique_ptr<ToolOutputFile> &outputFile : outputFiles)
- outputFile->keep();
- return 0;
-}
-
-int main(int argc, const char **argv) {
- toolName = sys::path::stem(argv[0]);
- cl::HideUnrelatedOptions({&cat});
- cl::ParseCommandLineOptions(
- argc, argv,
- "Split input into multiple parts separated by regex '^(.|//)--- ' and "
- "extract the part specified by '^(.|//)--- <part>'\n",
- nullptr,
- /*EnvVar=*/nullptr,
- /*LongOptionsUseDoubleDash=*/true);
-
- if (input.empty())
- fatal("", "input filename is not specified");
- if (output.empty())
- fatal("", "output directory is not specified");
- ErrorOr<std::unique_ptr<MemoryBuffer>> bufferOrErr =
- MemoryBuffer::getFileOrSTDIN(input);
- if (std::error_code ec = bufferOrErr.getError())
- fatal(input, ec.message());
-
- // Delete output if it is a file or an empty directory, so that we can create
- // a directory.
- sys::fs::file_status status;
- if (std::error_code ec = sys::fs::status(output, status))
- if (ec.value() != static_cast<int>(std::errc::no_such_file_or_directory))
- fatal(output, ec.message());
- if (status.type() != sys::fs::file_type::file_not_found &&
- status.type() != sys::fs::file_type::directory_file &&
- status.type() != sys::fs::file_type::regular_file)
- fatal(output, "output cannot be a special file");
- if (std::error_code ec = sys::fs::remove(output, /*IgnoreNonExisting=*/true))
- if (ec.value() != static_cast<int>(std::errc::directory_not_empty) &&
- ec.value() != static_cast<int>(std::errc::file_exists))
- fatal(output, ec.message());
- return handle(**bufferOrErr, input);
-}
diff --git a/src/llvm-project/llvm/tools/verify-uselistorder/verify-uselistorder.cpp b/src/llvm-project/llvm/tools/verify-uselistorder/verify-uselistorder.cpp
index e28c33d..9afe681 100644
--- a/src/llvm-project/llvm/tools/verify-uselistorder/verify-uselistorder.cpp
+++ b/src/llvm-project/llvm/tools/verify-uselistorder/verify-uselistorder.cpp
@@ -398,7 +398,7 @@
return;
// Generate random numbers between 10 and 99, which will line up nicely in
- // debug output. We're not worried about collisons here.
+ // debug output. We're not worried about collisions here.
LLVM_DEBUG(dbgs() << "V = "; V->dump());
std::uniform_int_distribution<short> Dist(10, 99);
SmallDenseMap<const Use *, short, 16> Order;
diff --git a/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp b/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp
index 8a44c44..ba1f54d 100644
--- a/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp
+++ b/src/llvm-project/llvm/tools/yaml2obj/yaml2obj.cpp
@@ -24,6 +24,7 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
#include <system_error>
using namespace llvm;
@@ -40,6 +41,9 @@
"definition. The syntax is <macro>=<definition>"),
cl::cat(Cat));
+cl::opt<bool> PreprocessOnly("E", cl::desc("Just print the preprocessed file"),
+ cl::cat(Cat));
+
cl::opt<unsigned>
DocNum("docnum", cl::init(1),
cl::desc("Read specified document from input (default = 1)"),
@@ -56,8 +60,8 @@
cl::Prefix, cl::cat(Cat));
} // namespace
-static Optional<std::string> preprocess(StringRef Buf,
- yaml::ErrorHandler ErrHandler) {
+static std::optional<std::string> preprocess(StringRef Buf,
+ yaml::ErrorHandler ErrHandler) {
DenseMap<StringRef, StringRef> Defines;
for (StringRef Define : D) {
StringRef Macro, Definition;
@@ -85,7 +89,7 @@
// When the -D option is requested, we use the provided value.
// Otherwise we use a default macro value if present.
auto It = Defines.find(Macro);
- Optional<StringRef> Value;
+ std::optional<StringRef> Value;
if (It != Defines.end())
Value = It->second;
else if (!Default.empty() || MacroExpr.endswith("="))
@@ -130,14 +134,20 @@
if (!Buf)
return 1;
- Optional<std::string> Buffer = preprocess(Buf.get()->getBuffer(), ErrHandler);
+ std::optional<std::string> Buffer =
+ preprocess(Buf.get()->getBuffer(), ErrHandler);
if (!Buffer)
return 1;
- yaml::Input YIn(*Buffer);
- if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum,
- MaxSize == 0 ? UINT64_MAX : MaxSize))
- return 1;
+ if (PreprocessOnly) {
+ Out->os() << Buffer;
+ } else {
+ yaml::Input YIn(*Buffer);
+
+ if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum,
+ MaxSize == 0 ? UINT64_MAX : MaxSize))
+ return 1;
+ }
Out->keep();
Out->os().flush();