[llvm] 80f30a6 - [ORC][C-bindings] Add access to LLJIT IRTransformLayer, ThreadSafeModule utils.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 18 18:52:44 PDT 2021


Author: Lang Hames
Date: 2021-06-19T11:50:27+10:00
New Revision: 80f30a6b855b7aa96b99205c986972483d75822e

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

LOG: [ORC][C-bindings] Add access to LLJIT IRTransformLayer, ThreadSafeModule utils.

This patch was derived from Valentin Churavy's work in
https://reviews.llvm.org/D104480. It adds support for setting the transform on
an IRTransformLayer, and for accessing the IRTransformLayer in LLJIT. It also
adds access to the ThreadSafeModule::withModuleDo method for thread-safe
access to modules.

A new example has been added to show how to use these APIs to optimize a module
during materialization.

Thanks Valentin!

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D103855

Added: 
    llvm/examples/OrcV2Examples/OrcV2CBindingsIRTransforms/CMakeLists.txt
    llvm/examples/OrcV2Examples/OrcV2CBindingsIRTransforms/OrcV2CBindingsIRTransforms.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 3c7301e06d797..e46448bed06f2 100644
--- a/llvm/examples/OrcV2Examples/CMakeLists.txt
+++ b/llvm/examples/OrcV2Examples/CMakeLists.txt
@@ -11,6 +11,7 @@ add_subdirectory(LLJITWithThinLTOSummaries)
 add_subdirectory(OrcV2CBindingsAddObjectFile)
 add_subdirectory(OrcV2CBindingsBasicUsage)
 add_subdirectory(OrcV2CBindingsDumpObjects)
+add_subdirectory(OrcV2CBindingsIRTransforms)
 add_subdirectory(OrcV2CBindingsReflectProcessSymbols)
 add_subdirectory(OrcV2CBindingsRemovableCode)
 

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

diff  --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsIRTransforms/OrcV2CBindingsIRTransforms.c b/llvm/examples/OrcV2Examples/OrcV2CBindingsIRTransforms/OrcV2CBindingsIRTransforms.c
new file mode 100644
index 0000000000000..f549f1c462b9c
--- /dev/null
+++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsIRTransforms/OrcV2CBindingsIRTransforms.c
@@ -0,0 +1,150 @@
+//===- 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 "llvm-c/Transforms/Scalar.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 myModuleTransform(void *Ctx, LLVMModuleRef Mod) {
+  LLVMPassManagerRef PM = LLVMCreatePassManager();
+  LLVMAddInstructionCombiningPass(PM);
+  LLVMRunPassManager(PM, Mod);
+  LLVMDisposePassManager(PM);
+  return LLVMErrorSuccess;
+}
+
+LLVMErrorRef transform(void *Ctx, LLVMOrcThreadSafeModuleRef *ModInOut,
+                       LLVMOrcMaterializationResponsibilityRef MR) {
+  return LLVMOrcThreadSafeModuleWithModuleDo(*ModInOut, myModuleTransform, Ctx);
+}
+
+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;
+    }
+  }
+
+  // Use TransformLayer to set IR transform.
+  {
+    LLVMOrcIRTransformLayerRef TL = LLVMOrcLLJITGetIRTransformLayer(J);
+    LLVMOrcLLJITIRTransformLayerSetTransform(TL, *transform, NULL);
+  }
+
+  // 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 37f4d4e94c498..d8156ccc1f553 100644
--- a/llvm/include/llvm-c/LLJIT.h
+++ b/llvm/include/llvm-c/LLJIT.h
@@ -222,6 +222,11 @@ LLVMOrcObjectLayerRef LLVMOrcLLJITGetObjLinkingLayer(LLVMOrcLLJITRef J);
 LLVMOrcObjectTransformLayerRef
 LLVMOrcLLJITGetObjTransformLayer(LLVMOrcLLJITRef J);
 
+/**
+ * Returns a non-owning reference to the LLJIT instance's IR transform layer.
+ */
+LLVMOrcIRTransformLayerRef LLVMOrcLLJITGetIRTransformLayer(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 6c7c9c9ee1f6d..9656c00075ec7 100644
--- a/llvm/include/llvm-c/Orc.h
+++ b/llvm/include/llvm-c/Orc.h
@@ -299,6 +299,13 @@ typedef struct LLVMOrcOpaqueThreadSafeContext *LLVMOrcThreadSafeContextRef;
  */
 typedef struct LLVMOrcOpaqueThreadSafeModule *LLVMOrcThreadSafeModuleRef;
 
+/**
+ * A function for inspecting/mutating IR modules, suitable for use with
+ * LLVMOrcThreadSafeModuleWithModuleDo.
+ */
+typedef LLVMErrorRef (*LLVMOrcGenericIRModuleOperationFunction)(
+    void *Ctx, LLVMModuleRef M);
+
 /**
  * A reference to an orc::JITTargetMachineBuilder instance.
  */
@@ -315,6 +322,30 @@ typedef struct LLVMOrcOpaqueObjectLayer *LLVMOrcObjectLayerRef;
  */
 typedef struct LLVMOrcOpaqueObjectLinkingLayer *LLVMOrcObjectLinkingLayerRef;
 
+/**
+ * A reference to an orc::IRTransformLayer instance.
+ */
+typedef struct LLVMOrcOpaqueIRTransformLayer *LLVMOrcIRTransformLayerRef;
+
+/**
+ * A function for applying transformations as part of an transform layer.
+ *
+ * Implementations of this type are responsible for managing the lifetime
+ * of the Module pointed to by ModInOut: If the LLVMModuleRef value is
+ * overwritten then the function is responsible for disposing of the incoming
+ * module. If the module is simply accessed/mutated in-place then ownership
+ * returns to the caller and the function does not need to do any lifetime
+ * management.
+ *
+ * Clients can call LLVMOrcLLJITGetIRTransformLayer to obtain the transform
+ * layer of a LLJIT instance, and use LLVMOrcLLJITIRTransformLayerSetTransform
+ * to set the function. This can be used to override the default transform
+ * layer.
+ */
+typedef LLVMErrorRef (*LLVMOrcIRTransformLayerTransformFunction)(
+    void *Ctx, LLVMOrcThreadSafeModuleRef *ModInOut,
+    LLVMOrcMaterializationResponsibilityRef MR);
+
 /**
  * A reference to an orc::ObjectTransformLayer instance.
  */
@@ -324,6 +355,13 @@ typedef struct LLVMOrcOpaqueObjectTransformLayer
 /**
  * A function for applying transformations to an object file buffer.
  *
+ * Implementations of this type are responsible for managing the lifetime
+ * of the memory buffer pointed to by ObjInOut: If the LLVMMemoryBufferRef
+ * value is overwritten then the function is responsible for disposing of the
+ * incoming buffer. If the buffer is simply accessed/mutated in-place then
+ * ownership returns to the caller and the function does not need to do any
+ * lifetime management.
+ *
  * The transform is allowed to return an error, in which case the ObjInOut
  * buffer should be disposed of and set to null.
  */
@@ -642,6 +680,14 @@ LLVMOrcCreateNewThreadSafeModule(LLVMModuleRef M,
  */
 void LLVMOrcDisposeThreadSafeModule(LLVMOrcThreadSafeModuleRef TSM);
 
+/**
+ * Apply the given function to the module contained in this ThreadSafeModule.
+ */
+LLVMErrorRef
+LLVMOrcThreadSafeModuleWithModuleDo(LLVMOrcThreadSafeModuleRef TSM,
+                                    LLVMOrcGenericIRModuleOperationFunction F,
+                                    void *Ctx);
+
 /**
  * Create a JITTargetMachineBuilder by detecting the host.
  *
@@ -733,6 +779,14 @@ void LLVMOrcObjectLayerEmit(LLVMOrcObjectLayerRef ObjLayer,
  */
 void LLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer);
 
+/**
+ * Set the transform function of the provided transform layer, passing through a
+ * pointer to user provided context.
+ */
+void LLVMOrcLLJITIRTransformLayerSetTransform(
+    LLVMOrcIRTransformLayerRef IRTransformLayer,
+    LLVMOrcIRTransformLayerTransformFunction TransformFunction, void *Ctx);
+
 /**
  * Set the transform function on an LLVMOrcObjectTransformLayer.
  */

diff  --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
index 39e722f8358fb..c6c0152cc9e45 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
@@ -94,6 +94,7 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITTargetMachineBuilder,
                                    LLVMOrcJITTargetMachineBuilderRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IRTransformLayer, LLVMOrcIRTransformLayerRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer,
                                    LLVMOrcObjectTransformLayerRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DumpObjects, LLVMOrcDumpObjectsRef)
@@ -427,6 +428,14 @@ void LLVMOrcDisposeThreadSafeContext(LLVMOrcThreadSafeContextRef TSCtx) {
   delete unwrap(TSCtx);
 }
 
+LLVMErrorRef
+LLVMOrcThreadSafeModuleWithModuleDo(LLVMOrcThreadSafeModuleRef TSM,
+                                    LLVMOrcGenericIRModuleOperationFunction F,
+                                    void *Ctx) {
+  return wrap(unwrap(TSM)->withModuleDo(
+      [&](Module &M) { return unwrap(F(Ctx, wrap(&M))); }));
+}
+
 LLVMOrcThreadSafeModuleRef
 LLVMOrcCreateNewThreadSafeModule(LLVMModuleRef M,
                                  LLVMOrcThreadSafeContextRef TSCtx) {
@@ -517,6 +526,23 @@ void LLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer) {
   delete unwrap(ObjLayer);
 }
 
+void LLVMOrcLLJITIRTransformLayerSetTransform(
+    LLVMOrcIRTransformLayerRef IRTransformLayer,
+    LLVMOrcIRTransformLayerTransformFunction TransformFunction, void *Ctx) {
+  unwrap(IRTransformLayer)
+      ->setTransform(
+          [=](ThreadSafeModule TSM,
+              MaterializationResponsibility &R) -> Expected<ThreadSafeModule> {
+            LLVMOrcThreadSafeModuleRef TSMRef =
+                wrap(new ThreadSafeModule(std::move(TSM)));
+            if (LLVMErrorRef Err = TransformFunction(Ctx, &TSMRef, wrap(&R))) {
+              assert(!TSMRef && "TSMRef was not reset to null on error");
+              return unwrap(Err);
+            }
+            return std::move(*unwrap(TSMRef));
+          });
+}
+
 void LLVMOrcObjectTransformLayerSetTransform(
     LLVMOrcObjectTransformLayerRef ObjTransformLayer,
     LLVMOrcObjectTransformLayerTransformFunction TransformFunction, void *Ctx) {
@@ -695,3 +721,7 @@ void LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(
   reinterpret_cast<RTDyldObjectLinkingLayer *>(unwrap(RTDyldObjLinkingLayer))
       ->registerJITEventListener(*unwrap(Listener));
 }
+
+LLVMOrcIRTransformLayerRef LLVMOrcLLJITGetIRTransformLayer(LLVMOrcLLJITRef J) {
+  return wrap(&unwrap(J)->getIRTransformLayer());
+}


        


More information about the llvm-commits mailing list