[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