[llvm] 16f38dd - [ORC] Add a utility to support dumping JIT'd objects to disk for debugging.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 14 21:27:26 PST 2019
Author: Lang Hames
Date: 2019-11-14T21:27:19-08:00
New Revision: 16f38dda292c6e2963e77f722042a9eb5da56d28
URL: https://github.com/llvm/llvm-project/commit/16f38dda292c6e2963e77f722042a9eb5da56d28
DIFF: https://github.com/llvm/llvm-project/commit/16f38dda292c6e2963e77f722042a9eb5da56d28.diff
LOG: [ORC] Add a utility to support dumping JIT'd objects to disk for debugging.
Adds a DumpObjects utility that can be used to dump JIT'd objects to disk.
Instances of DebugObjects may be used by ObjectTransformLayer as no-op
transforms.
This patch also adds an ObjectTransformLayer to LLJIT and an example of how
to use this utility to dump JIT'd objects in LLJIT.
Added:
llvm/examples/LLJITExamples/LLJITDumpObjects/CMakeLists.txt
llvm/examples/LLJITExamples/LLJITDumpObjects/LLJITDumpObjects.cpp
llvm/include/llvm/ExecutionEngine/Orc/DebugUtils.h
llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp
Modified:
llvm/examples/LLJITExamples/CMakeLists.txt
llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h
llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp
Removed:
################################################################################
diff --git a/llvm/examples/LLJITExamples/CMakeLists.txt b/llvm/examples/LLJITExamples/CMakeLists.txt
index d1d53028f896..2ae0a5a22ba9 100644
--- a/llvm/examples/LLJITExamples/CMakeLists.txt
+++ b/llvm/examples/LLJITExamples/CMakeLists.txt
@@ -1,2 +1,3 @@
+add_subdirectory(LLJITDumpObjects)
add_subdirectory(LLJITWithObjectCache)
add_subdirectory(LLJITWithJITLink)
diff --git a/llvm/examples/LLJITExamples/LLJITDumpObjects/CMakeLists.txt b/llvm/examples/LLJITExamples/LLJITDumpObjects/CMakeLists.txt
new file mode 100644
index 000000000000..bf3bc7193ae5
--- /dev/null
+++ b/llvm/examples/LLJITExamples/LLJITDumpObjects/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(LLVM_LINK_COMPONENTS
+ Core
+ ExecutionEngine
+ IRReader
+ OrcJIT
+ Support
+ nativecodegen
+ )
+
+add_llvm_example(LLJITDumpObjects
+ LLJITDumpObjects.cpp
+ )
diff --git a/llvm/examples/LLJITExamples/LLJITDumpObjects/LLJITDumpObjects.cpp b/llvm/examples/LLJITExamples/LLJITDumpObjects/LLJITDumpObjects.cpp
new file mode 100644
index 000000000000..875292a2e091
--- /dev/null
+++ b/llvm/examples/LLJITExamples/LLJITDumpObjects/LLJITDumpObjects.cpp
@@ -0,0 +1,70 @@
+//===----- LLJITDumpObjects.cpp - How to dump JIT'd objects with LLJIT ----===//
+//
+// 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/StringMap.h"
+#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "../ExampleModules.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+ExitOnError ExitOnErr;
+
+cl::opt<bool> DumpJITdObjects("dump-jitted-objects",
+ cl::desc("dump jitted objects"), cl::Optional,
+ cl::init(true));
+
+cl::opt<std::string> DumpDir("dump-dir",
+ cl::desc("directory to dump objects to"),
+ cl::Optional, cl::init(""));
+
+cl::opt<std::string> DumpFileStem("dump-file-stem",
+ cl::desc("Override default dump names"),
+ cl::Optional, cl::init(""));
+
+int main(int argc, char *argv[]) {
+ // Initialize LLVM.
+ InitLLVM X(argc, argv);
+
+ InitializeNativeTarget();
+ InitializeNativeTargetAsmPrinter();
+
+ cl::ParseCommandLineOptions(argc, argv, "HowToUseLLJIT");
+ ExitOnErr.setBanner(std::string(argv[0]) + ": ");
+
+ outs()
+ << "Usage notes:\n"
+ " Use -debug-only=orc on debug builds to see log messages of objects "
+ "being dumped\n"
+ " Specify -dump-dir to specify a dump directory\n"
+ " Specify -dump-file-stem to override the dump file stem\n"
+ " Specify -dump-jitted-objects=false to disable dumping\n";
+
+ auto J = ExitOnErr(LLJITBuilder().create());
+
+ if (DumpJITdObjects)
+ J->getObjTransformLayer().setTransform(DumpObjects(DumpDir, DumpFileStem));
+
+ auto M = ExitOnErr(parseExampleModule(Add1Example, "add1"));
+
+ ExitOnErr(J->addIRModule(std::move(M)));
+
+ // Look up the JIT'd function, cast it to a function pointer, then call it.
+ auto Add1Sym = ExitOnErr(J->lookup("add1"));
+ int (*Add1)(int) = (int (*)(int))Add1Sym.getAddress();
+
+ int Result = Add1(42);
+ outs() << "add1(42) = " << Result << "\n";
+
+ return 0;
+}
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/DebugUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/DebugUtils.h
new file mode 100644
index 000000000000..b2ef29d65ffe
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/DebugUtils.h
@@ -0,0 +1,58 @@
+//===----- DebugUtils.h - Utilities for debugging ORC JITs ------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for debugging ORC-based JITs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGUTILS_H
+#define LLVM_EXECUTIONENGINE_ORC_DEBUGUTILS_H
+
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <string>
+
+namespace llvm {
+
+class MemoryBuffer;
+
+namespace orc {
+
+/// A function object that can be used as an ObjectTransformLayer transform
+/// to dump object files to disk at a specified path.
+class DumpObjects {
+public:
+ /// Construct a DumpObjects transform that will dump objects to disk.
+ ///
+ /// @param DumpDir specifies the path to write dumped objects to. DumpDir may
+ /// be empty, in which case files will be dumped to the working directory. If
+ /// DumpDir is non-empty then any trailing separators will be discarded.
+ ///
+ /// @param IdentifierOverride specifies a file name stem to use when dumping
+ /// objects. If empty, each MemoryBuffer's identifier will be used (with a .o
+ /// suffix added if not already present). If an identifier override is
+ /// supplied it will be used instead (since all buffers will use the same
+ /// identifier, the resulting files will be named <ident>.o, <ident>.2.o,
+ /// <ident>.3.o, and so on). IdentifierOverride should not contain an
+ /// extension, as a .o suffix will be added by DumpObjects.
+ DumpObjects(std::string DumpDir = "", std::string IdentifierOverride = "");
+
+ /// Dumps the given buffer to disk.
+ Expected<std::unique_ptr<MemoryBuffer>>
+ operator()(std::unique_ptr<MemoryBuffer> Obj);
+
+private:
+ StringRef getBufferIdentifier(MemoryBuffer &B);
+ std::string DumpDir;
+ std::string IdentifierOverride;
+};
+
+} // End namespace orc
+} // End namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_DEBUGUTILS_H
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
index b1e47d77557c..c048ff3d5522 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
@@ -117,6 +117,9 @@ class LLJIT {
/// Returns a reference to the ObjLinkingLayer
ObjectLayer &getObjLinkingLayer() { return *ObjLinkingLayer; }
+ /// Returns a reference to the object transform layer.
+ ObjectTransformLayer &getObjTransformLayer() { return ObjTransformLayer; }
+
protected:
static std::unique_ptr<ObjectLayer>
createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES);
@@ -140,6 +143,7 @@ class LLJIT {
std::unique_ptr<ThreadPool> CompileThreads;
std::unique_ptr<ObjectLayer> ObjLinkingLayer;
+ ObjectTransformLayer ObjTransformLayer;
std::unique_ptr<IRCompileLayer> CompileLayer;
CtorDtorRunner CtorRunner, DtorRunner;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h
index eac1cc3e097a..bf989cc8677c 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h
@@ -29,11 +29,15 @@ class ObjectTransformLayer : public ObjectLayer {
std::unique_ptr<MemoryBuffer>)>;
ObjectTransformLayer(ExecutionSession &ES, ObjectLayer &BaseLayer,
- TransformFunction Transform);
+ TransformFunction Transform = TransformFunction());
void emit(MaterializationResponsibility R,
std::unique_ptr<MemoryBuffer> O) override;
+ void setTransform(TransformFunction Transform) {
+ this->Transform = std::move(Transform);
+ }
+
private:
ObjectLayer &BaseLayer;
TransformFunction Transform;
diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index e615fd8f2347..4a18f8847444 100644
--- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_library(LLVMOrcJIT
CompileOnDemandLayer.cpp
CompileUtils.cpp
Core.cpp
+ DebugUtils.cpp
ExecutionUtils.cpp
IndirectionUtils.cpp
IRCompileLayer.cpp
diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
index f8251627a4ef..f5671d90420a 100644
--- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
@@ -43,8 +43,7 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
}
auto ObjBuffer = std::make_unique<SmallVectorMemoryBuffer>(
- std::move(ObjBufferSV),
- "<in memory object compiled from " + M.getModuleIdentifier() + ">");
+ std::move(ObjBufferSV), M.getModuleIdentifier() + "-jitted-objectbuffer");
auto Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
diff --git a/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp b/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp
new file mode 100644
index 000000000000..4e573dad118a
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp
@@ -0,0 +1,68 @@
+//===---------- DebugUtils.cpp - Utilities for debugging ORC JITs ---------===//
+//
+// 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/ExecutionEngine/Orc/DebugUtils.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "orc"
+
+namespace llvm {
+namespace orc {
+
+DumpObjects::DumpObjects(std::string DumpDir, std::string IdentifierOverride)
+ : DumpDir(std::move(DumpDir)),
+ IdentifierOverride(std::move(IdentifierOverride)) {
+
+ /// Discard any trailing separators.
+ while (!this->DumpDir.empty() &&
+ sys::path::is_separator(this->DumpDir.back()))
+ this->DumpDir.pop_back();
+}
+
+Expected<std::unique_ptr<MemoryBuffer>>
+DumpObjects::operator()(std::unique_ptr<MemoryBuffer> Obj) {
+ size_t Idx = 1;
+
+ std::string DumpPathStem;
+ raw_string_ostream(DumpPathStem)
+ << DumpDir << (DumpDir.empty() ? "" : "/") << getBufferIdentifier(*Obj);
+
+ std::string DumpPath = DumpPathStem + ".o";
+ while (sys::fs::exists(DumpPath)) {
+ DumpPath.clear();
+ raw_string_ostream(DumpPath) << DumpPathStem << "." << (++Idx) << ".o";
+ }
+
+ LLVM_DEBUG({
+ dbgs() << "Dumping object buffer [ " << (void *)Obj->getBufferStart()
+ << " -- " << (void *)(Obj->getBufferEnd() - 1) << " ] to "
+ << DumpPath << "\n";
+ });
+
+ std::error_code EC;
+ raw_fd_ostream DumpStream(DumpPath, EC);
+ if (EC)
+ return errorCodeToError(EC);
+ DumpStream.write(Obj->getBufferStart(), Obj->getBufferSize());
+
+ return Obj;
+}
+
+StringRef DumpObjects::getBufferIdentifier(MemoryBuffer &B) {
+ if (!IdentifierOverride.empty())
+ return IdentifierOverride;
+ StringRef Identifier = B.getBufferIdentifier();
+ Identifier.consume_back(".o");
+ return Identifier;
+}
+
+} // End namespace orc.
+} // End namespace llvm.
diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
index a80f78afe80f..03f22e0c2a2a 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
@@ -51,7 +51,7 @@ Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) {
Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj) {
assert(Obj && "Can not add null object");
- return ObjLinkingLayer->add(JD, std::move(Obj), ES->allocateVModule());
+ return ObjTransformLayer.add(JD, std::move(Obj), ES->allocateVModule());
}
Expected<JITEvaluatedSymbol> LLJIT::lookupLinkerMangled(JITDylib &JD,
@@ -103,13 +103,13 @@ LLJIT::createCompileFunction(LLJITBuilderState &S,
LLJIT::LLJIT(LLJITBuilderState &S, Error &Err)
: ES(S.ES ? std::move(S.ES) : std::make_unique<ExecutionSession>()),
- Main(this->ES->getMainJITDylib()), DL(""), CtorRunner(Main),
+ Main(this->ES->getMainJITDylib()), DL(""),
+ ObjLinkingLayer(createObjectLinkingLayer(S, *ES)),
+ ObjTransformLayer(*this->ES, *ObjLinkingLayer), CtorRunner(Main),
DtorRunner(Main) {
ErrorAsOutParameter _(&Err);
- ObjLinkingLayer = createObjectLinkingLayer(S, *ES);
-
if (auto DLOrErr = S.JTMB->getDefaultDataLayoutForTarget())
DL = std::move(*DLOrErr);
else {
@@ -124,7 +124,7 @@ LLJIT::LLJIT(LLJITBuilderState &S, Error &Err)
return;
}
CompileLayer = std::make_unique<IRCompileLayer>(
- *ES, *ObjLinkingLayer, std::move(*CompileFunction));
+ *ES, ObjTransformLayer, std::move(*CompileFunction));
}
if (S.NumCompileThreads > 0) {
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp
index 815517321b76..d18eb38a4142 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp
@@ -21,12 +21,18 @@ void ObjectTransformLayer::emit(MaterializationResponsibility R,
std::unique_ptr<MemoryBuffer> O) {
assert(O && "Module must not be null");
- if (auto TransformedObj = Transform(std::move(O)))
- BaseLayer.emit(std::move(R), std::move(*TransformedObj));
- else {
- R.failMaterialization();
- getExecutionSession().reportError(TransformedObj.takeError());
+ // If there is a transform set then apply it.
+ if (Transform) {
+ if (auto TransformedObj = Transform(std::move(O)))
+ O = std::move(*TransformedObj);
+ else {
+ R.failMaterialization();
+ getExecutionSession().reportError(TransformedObj.takeError());
+ return;
+ }
}
+
+ BaseLayer.emit(std::move(R), std::move(O));
}
} // End namespace orc.
More information about the llvm-commits
mailing list