[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