[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