[llvm] cec8e69 - [ORC] Add support for dumping objects to the C API.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 18 03:56:55 PDT 2021


Author: Lang Hames
Date: 2021-06-18T20:56:45+10:00
New Revision: cec8e69f01c3374cb38c6683058381b96fab8f89

URL: https://github.com/llvm/llvm-project/commit/cec8e69f01c3374cb38c6683058381b96fab8f89
DIFF: https://github.com/llvm/llvm-project/commit/cec8e69f01c3374cb38c6683058381b96fab8f89.diff

LOG: [ORC] Add support for dumping objects to the C API.

Provides ObjectTransformLayer APIs, a getter to access the
ObjectTransformLayer member of LLJIT, and the DumpObjects utility
to make construction of a dump-to-disk transform easy.

An example showing how the new APIs can be used has been added in
llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects.

Added: 
    llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/CMakeLists.txt
    llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/OrcV2CBindingsDumpObjects.c

Modified: 
    llvm/examples/OrcV2Examples/CMakeLists.txt
    llvm/include/llvm-c/LLJIT.h
    llvm/include/llvm-c/Orc.h
    llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/examples/OrcV2Examples/CMakeLists.txt b/llvm/examples/OrcV2Examples/CMakeLists.txt
index f6a11d6f0ef20..3c7301e06d797 100644
--- a/llvm/examples/OrcV2Examples/CMakeLists.txt
+++ b/llvm/examples/OrcV2Examples/CMakeLists.txt
@@ -10,6 +10,7 @@ add_subdirectory(LLJITWithTargetProcessControl)
 add_subdirectory(LLJITWithThinLTOSummaries)
 add_subdirectory(OrcV2CBindingsAddObjectFile)
 add_subdirectory(OrcV2CBindingsBasicUsage)
+add_subdirectory(OrcV2CBindingsDumpObjects)
 add_subdirectory(OrcV2CBindingsReflectProcessSymbols)
 add_subdirectory(OrcV2CBindingsRemovableCode)
 

diff  --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/CMakeLists.txt b/llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/CMakeLists.txt
new file mode 100644
index 0000000000000..8e2c97d782062
--- /dev/null
+++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS
+  Core
+  ExecutionEngine
+  IRReader
+  JITLink
+  MC
+  OrcJIT
+  Support
+  Target
+  nativecodegen
+  )
+
+add_llvm_example(OrcV2CBindingsDumpObjects
+  OrcV2CBindingsDumpObjects.c
+  )

diff  --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/OrcV2CBindingsDumpObjects.c b/llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/OrcV2CBindingsDumpObjects.c
new file mode 100644
index 0000000000000..1a90138d20364
--- /dev/null
+++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsDumpObjects/OrcV2CBindingsDumpObjects.c
@@ -0,0 +1,140 @@
+//===- OrcV2CBindingsDumpObjects.c - Dump JIT'd objects to disk via C API -===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// To run the demo build 'OrcV2CBindingsDumpObjects', then run the built
+// program. It will execute as for OrcV2CBindingsBasicUsage, but will write
+// a single JIT'd object out to the working directory.
+//
+// Try experimenting with the DumpDir and IdentifierOverride arguments to
+// LLVMOrcCreateDumpObjects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/Core.h"
+#include "llvm-c/Error.h"
+#include "llvm-c/Initialization.h"
+#include "llvm-c/LLJIT.h"
+#include "llvm-c/Support.h"
+#include "llvm-c/Target.h"
+
+#include <stdio.h>
+
+int handleError(LLVMErrorRef Err) {
+  char *ErrMsg = LLVMGetErrorMessage(Err);
+  fprintf(stderr, "Error: %s\n", ErrMsg);
+  LLVMDisposeErrorMessage(ErrMsg);
+  return 1;
+}
+
+LLVMOrcThreadSafeModuleRef createDemoModule() {
+  LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
+  LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
+  LLVMModuleRef M = LLVMModuleCreateWithNameInContext("demo", Ctx);
+  LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()};
+  LLVMTypeRef SumFunctionType =
+      LLVMFunctionType(LLVMInt32Type(), ParamTypes, 2, 0);
+  LLVMValueRef SumFunction = LLVMAddFunction(M, "sum", SumFunctionType);
+  LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(SumFunction, "entry");
+  LLVMBuilderRef Builder = LLVMCreateBuilder();
+  LLVMPositionBuilderAtEnd(Builder, EntryBB);
+  LLVMValueRef SumArg0 = LLVMGetParam(SumFunction, 0);
+  LLVMValueRef SumArg1 = LLVMGetParam(SumFunction, 1);
+  LLVMValueRef Result = LLVMBuildAdd(Builder, SumArg0, SumArg1, "result");
+  LLVMBuildRet(Builder, Result);
+  LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
+  LLVMOrcDisposeThreadSafeContext(TSCtx);
+  return TSM;
+}
+
+LLVMErrorRef dumpObjectsTransform(LLVMMemoryBufferRef *ObjInOut, void *Ctx) {
+  LLVMOrcDumpObjectsRef DumpObjects = *(LLVMOrcDumpObjectsRef *)Ctx;
+  return LLVMOrcDumpObjects_CallOperator(DumpObjects, ObjInOut);
+}
+
+int main(int argc, char *argv[]) {
+
+  int MainResult = 0;
+
+  LLVMParseCommandLineOptions(argc, (const char **)argv, "");
+  LLVMInitializeCore(LLVMGetGlobalPassRegistry());
+
+  LLVMInitializeNativeTarget();
+  LLVMInitializeNativeAsmPrinter();
+
+  // Create a DumpObjects instance to use when dumping objects to disk.
+  LLVMOrcDumpObjectsRef DumpObjects = LLVMOrcCreateDumpObjects("", "");
+
+  // Create the JIT instance.
+  LLVMOrcLLJITRef J;
+  {
+    LLVMErrorRef Err;
+    if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
+      MainResult = handleError(Err);
+      goto llvm_shutdown;
+    }
+  }
+
+  // Set an object transform to call our DumpObjects instance for every
+  // JIT'd object.
+  LLVMOrcObjectTransformLayerSetTransform(LLVMOrcLLJITGetObjTransformLayer(J),
+                                          dumpObjectsTransform, &DumpObjects);
+
+  // Create our demo module.
+  LLVMOrcThreadSafeModuleRef TSM = createDemoModule();
+
+  // Add our demo module to the JIT.
+  {
+    LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
+    LLVMErrorRef Err;
+    if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, TSM))) {
+      // If adding the ThreadSafeModule fails then we need to clean it up
+      // ourselves. If adding it succeeds the JIT will manage the memory.
+      LLVMOrcDisposeThreadSafeModule(TSM);
+      MainResult = handleError(Err);
+      goto jit_cleanup;
+    }
+  }
+
+  // Look up the address of our demo entry point.
+  LLVMOrcJITTargetAddress SumAddr;
+  {
+    LLVMErrorRef Err;
+    if ((Err = LLVMOrcLLJITLookup(J, &SumAddr, "sum"))) {
+      MainResult = handleError(Err);
+      goto jit_cleanup;
+    }
+  }
+
+  // If we made it here then everything succeeded. Execute our JIT'd code.
+  int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr;
+  int32_t Result = Sum(1, 2);
+
+  // Print the result.
+  printf("1 + 2 = %i\n", Result);
+
+jit_cleanup:
+
+  // Destroy our JIT instance.
+  {
+    LLVMErrorRef Err;
+    if ((Err = LLVMOrcDisposeLLJIT(J))) {
+      int NewFailureResult = handleError(Err);
+      if (MainResult == 0)
+        MainResult = NewFailureResult;
+    }
+  }
+
+llvm_shutdown:
+  // Destroy our DumpObjects instance.
+  LLVMOrcDisposeDumpObjects(DumpObjects);
+
+  // Shut down LLVM.
+  LLVMShutdown();
+
+  return MainResult;
+}

diff  --git a/llvm/include/llvm-c/LLJIT.h b/llvm/include/llvm-c/LLJIT.h
index b140a5d058811..37f4d4e94c498 100644
--- a/llvm/include/llvm-c/LLJIT.h
+++ b/llvm/include/llvm-c/LLJIT.h
@@ -216,6 +216,12 @@ LLVMErrorRef LLVMOrcLLJITLookup(LLVMOrcLLJITRef J,
  */
 LLVMOrcObjectLayerRef LLVMOrcLLJITGetObjLinkingLayer(LLVMOrcLLJITRef J);
 
+/**
+ * Returns a non-owning reference to the LLJIT instance's object linking layer.
+ */
+LLVMOrcObjectTransformLayerRef
+LLVMOrcLLJITGetObjTransformLayer(LLVMOrcLLJITRef J);
+
 LLVM_C_EXTERN_C_END
 
 #endif /* LLVM_C_LLJIT_H */

diff  --git a/llvm/include/llvm-c/Orc.h b/llvm/include/llvm-c/Orc.h
index 612c80bae6611..4b942b2d12d2d 100644
--- a/llvm/include/llvm-c/Orc.h
+++ b/llvm/include/llvm-c/Orc.h
@@ -315,6 +315,29 @@ typedef struct LLVMOrcOpaqueObjectLayer *LLVMOrcObjectLayerRef;
  */
 typedef struct LLVMOrcOpaqueObjectLinkingLayer *LLVMOrcObjectLinkingLayerRef;
 
+/**
+ * A reference to an orc::ObjectTransformLayer instance.
+ */
+typedef struct LLVMOrcOpaqueObjectTransformLayer
+    *LLVMOrcObjectTransformLayerRef;
+
+/**
+ * A function for applying transformations to an object file buffer.
+ *
+ * The transform is allowed to return an error, in which case the ObjInOut
+ * buffer should be disposed of and set to null.
+ */
+typedef LLVMErrorRef (*LLVMOrcObjectTransformLayerTransformFunction)(
+    LLVMMemoryBufferRef *ObjInOut, void *Ctx);
+
+/**
+ * A reference to an orc::DumpObjects object.
+ *
+ * Can be used to dump object files to disk with unique names. Useful as an
+ * ObjectTransformLayer transform.
+ */
+typedef struct LLVMOrcOpaqueDumpObjects *LLVMOrcDumpObjectsRef;
+
 /**
  * Attach a custom error reporter function to the ExecutionSession.
  *
@@ -710,6 +733,41 @@ void LLVMOrcObjectLayerEmit(LLVMOrcObjectLayerRef ObjLayer,
  */
 void LLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer);
 
+/**
+ * Set the transform function on an LLVMOrcObjectTransformLayer.
+ */
+void LLVMOrcObjectTransformLayerSetTransform(
+    LLVMOrcObjectTransformLayerRef ObjTransformLayer,
+    LLVMOrcObjectTransformLayerTransformFunction TransformFunction, void *Ctx);
+
+/**
+ * Create a DumpObjects instance.
+ *
+ * DumpDir specifies the path to write dumped objects to. DumpDir may be empty
+ * in which case files will be dumped to the working directory.
+ *
+ * IdentifierOverride specifies a file name stem to use when dumping objects.
+ * If empty then 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, along with an incrementing counter (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.
+ */
+LLVMOrcDumpObjectsRef LLVMOrcCreateDumpObjects(const char *DumpDir,
+                                               const char *IdentifierOverride);
+
+/**
+ * Dispose of a DumpObjects instance.
+ */
+void LLVMOrcDisposeDumpObjects(LLVMOrcDumpObjectsRef DumpObjects);
+
+/**
+ * Dump the contents of the given MemoryBuffer.
+ */
+LLVMErrorRef LLVMOrcDumpObjects_CallOperator(LLVMOrcDumpObjectsRef DumpObjects,
+                                             LLVMMemoryBufferRef *ObjBuffer);
+
 LLVM_C_EXTERN_C_END
 
 #endif /* LLVM_C_ORC_H */

diff  --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
index 3c6bd8fa4ac05..71e260f8caf09 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
@@ -13,6 +13,7 @@
 
 #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 
@@ -93,6 +94,9 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITTargetMachineBuilder,
                                    LLVMOrcJITTargetMachineBuilderRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer,
+                                   LLVMOrcObjectTransformLayerRef)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DumpObjects, LLVMOrcDumpObjectsRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef)
 
@@ -513,6 +517,44 @@ void LLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer) {
   delete unwrap(ObjLayer);
 }
 
+void LLVMOrcObjectTransformLayerSetTransform(
+    LLVMOrcObjectTransformLayerRef ObjTransformLayer,
+    LLVMOrcObjectTransformLayerTransformFunction TransformFunction, void *Ctx) {
+  unwrap(ObjTransformLayer)
+      ->setTransform([TransformFunction, Ctx](std::unique_ptr<MemoryBuffer> Obj)
+                         -> Expected<std::unique_ptr<MemoryBuffer>> {
+        LLVMMemoryBufferRef ObjBuffer = wrap(Obj.release());
+        if (LLVMErrorRef Err = TransformFunction(&ObjBuffer, Ctx)) {
+          assert(!ObjBuffer && "ObjBuffer was not reset to null on error");
+          return unwrap(Err);
+        }
+        return std::unique_ptr<MemoryBuffer>(unwrap(ObjBuffer));
+      });
+}
+
+LLVMOrcDumpObjectsRef LLVMOrcCreateDumpObjects(const char *DumpDir,
+                                               const char *IdentifierOverride) {
+  assert(DumpDir && "DumpDir should not be null");
+  assert(IdentifierOverride && "IdentifierOverride should not be null");
+  return wrap(new DumpObjects(DumpDir, IdentifierOverride));
+}
+
+void LLVMOrcDisposeDumpObjects(LLVMOrcDumpObjectsRef DumpObjects) {
+  delete unwrap(DumpObjects);
+}
+
+LLVMErrorRef LLVMOrcDumpObjects_CallOperator(LLVMOrcDumpObjectsRef DumpObjects,
+                                             LLVMMemoryBufferRef *ObjBuffer) {
+  std::unique_ptr<MemoryBuffer> OB(unwrap(*ObjBuffer));
+  if (auto Result = (*unwrap(DumpObjects))(std::move(OB))) {
+    *ObjBuffer = wrap(Result->release());
+    return LLVMErrorSuccess;
+  } else {
+    *ObjBuffer = nullptr;
+    return wrap(Result.takeError());
+  }
+}
+
 LLVMOrcLLJITBuilderRef LLVMOrcCreateLLJITBuilder(void) {
   return wrap(new LLJITBuilder());
 }
@@ -632,6 +674,11 @@ LLVMOrcObjectLayerRef LLVMOrcLLJITGetObjLinkingLayer(LLVMOrcLLJITRef J) {
   return wrap(&unwrap(J)->getObjLinkingLayer());
 }
 
+LLVMOrcObjectTransformLayerRef
+LLVMOrcLLJITGetObjTransformLayer(LLVMOrcLLJITRef J) {
+  return wrap(&unwrap(J)->getObjTransformLayer());
+}
+
 LLVMOrcObjectLayerRef
 LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(
     LLVMOrcExecutionSessionRef ES) {


        


More information about the llvm-commits mailing list