diff --git a/llvm/examples/OrcV2Examples/CMakeLists.txt b/llvm/examples/OrcV2Examples/CMakeLists.txt index 3c7301e06d797a..e46448bed06f21 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 00000000000000..bc3734bd4c4f51 --- /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 00000000000000..f549f1c462b9cc --- /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 + +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 37f4d4e94c4989..d8156ccc1f5530 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 6c7c9c9ee1f6de..9656c00075ec79 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 39e722f8358fb8..c6c0152cc9e45b 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 { + 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(unwrap(RTDyldObjLinkingLayer)) ->registerJITEventListener(*unwrap(Listener)); } + +LLVMOrcIRTransformLayerRef LLVMOrcLLJITGetIRTransformLayer(LLVMOrcLLJITRef J) { + return wrap(&unwrap(J)->getIRTransformLayer()); +}