forked from OSchip/llvm-project
Expose the RTDyldMemoryManager through the C API. This allows clients of
the C API to provide their own way of allocating JIT memory (both code and data) and finalizing memory permissions (page protections, cache flush). llvm-svn: 182408
This commit is contained in:
parent
34b9ee6f3b
commit
e1e3f7cc01
|
@ -411,6 +411,7 @@ void LLVMShutdown();
|
||||||
|
|
||||||
/*===-- Error handling ----------------------------------------------------===*/
|
/*===-- Error handling ----------------------------------------------------===*/
|
||||||
|
|
||||||
|
char *LLVMCreateMessage(const char *Message);
|
||||||
void LLVMDisposeMessage(char *Message);
|
void LLVMDisposeMessage(char *Message);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,14 @@ void LLVMLinkInInterpreter(void);
|
||||||
|
|
||||||
typedef struct LLVMOpaqueGenericValue *LLVMGenericValueRef;
|
typedef struct LLVMOpaqueGenericValue *LLVMGenericValueRef;
|
||||||
typedef struct LLVMOpaqueExecutionEngine *LLVMExecutionEngineRef;
|
typedef struct LLVMOpaqueExecutionEngine *LLVMExecutionEngineRef;
|
||||||
|
typedef struct LLVMOpaqueMCJITMemoryManager *LLVMMCJITMemoryManagerRef;
|
||||||
|
|
||||||
struct LLVMMCJITCompilerOptions {
|
struct LLVMMCJITCompilerOptions {
|
||||||
unsigned OptLevel;
|
unsigned OptLevel;
|
||||||
LLVMCodeModel CodeModel;
|
LLVMCodeModel CodeModel;
|
||||||
LLVMBool NoFramePointerElim;
|
LLVMBool NoFramePointerElim;
|
||||||
LLVMBool EnableFastISel;
|
LLVMBool EnableFastISel;
|
||||||
|
LLVMMCJITMemoryManagerRef MCJMM;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*===-- Operations on generic values --------------------------------------===*/
|
/*===-- Operations on generic values --------------------------------------===*/
|
||||||
|
@ -167,6 +169,32 @@ void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
|
||||||
|
|
||||||
void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global);
|
void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global);
|
||||||
|
|
||||||
|
/*===-- Operations on memory managers -------------------------------------===*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a simple custom MCJIT memory manager. This memory manager can
|
||||||
|
* intercept allocations in a module-oblivious way. This will return NULL
|
||||||
|
* if any of the passed functions are NULL.
|
||||||
|
*
|
||||||
|
* @param Opaque An opaque client object to pass back to the callbacks.
|
||||||
|
* @param AllocateCodeSection Allocate a block of memory for executable code.
|
||||||
|
* @param AllocateDataSection Allocate a block of memory for data.
|
||||||
|
* @param FinalizeMemory Set page permissions and flush cache. Return 0 on
|
||||||
|
* success, 1 on error.
|
||||||
|
*/
|
||||||
|
LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager(
|
||||||
|
void *Opaque,
|
||||||
|
uint8_t *(*AllocateCodeSection)(void *Opaque,
|
||||||
|
uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID),
|
||||||
|
uint8_t *(*AllocateDataSection)(void *Opaque,
|
||||||
|
uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID, LLVMBool IsReadOnly),
|
||||||
|
LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg),
|
||||||
|
void (*Destroy)(void *Opaque));
|
||||||
|
|
||||||
|
void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -71,6 +71,10 @@ public:
|
||||||
virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0;
|
virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create wrappers for C Binding types (see CBindingWrapping.h).
|
||||||
|
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(
|
||||||
|
RTDyldMemoryManager, LLVMMCJITMemoryManagerRef)
|
||||||
|
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
|
#endif // LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "llvm-c/ExecutionEngine.h"
|
#include "llvm-c/ExecutionEngine.h"
|
||||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||||
|
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
@ -157,10 +158,8 @@ LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
|
||||||
void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions,
|
void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions,
|
||||||
size_t SizeOfPassedOptions) {
|
size_t SizeOfPassedOptions) {
|
||||||
LLVMMCJITCompilerOptions options;
|
LLVMMCJITCompilerOptions options;
|
||||||
options.OptLevel = 0;
|
memset(&options, 0, sizeof(options)); // Most fields are zero by default.
|
||||||
options.CodeModel = LLVMCodeModelJITDefault;
|
options.CodeModel = LLVMCodeModelJITDefault;
|
||||||
options.NoFramePointerElim = false;
|
|
||||||
options.EnableFastISel = false;
|
|
||||||
|
|
||||||
memcpy(PassedOptions, &options,
|
memcpy(PassedOptions, &options,
|
||||||
std::min(sizeof(options), SizeOfPassedOptions));
|
std::min(sizeof(options), SizeOfPassedOptions));
|
||||||
|
@ -199,6 +198,8 @@ LLVMBool LLVMCreateMCJITCompilerForModule(
|
||||||
.setOptLevel((CodeGenOpt::Level)options.OptLevel)
|
.setOptLevel((CodeGenOpt::Level)options.OptLevel)
|
||||||
.setCodeModel(unwrap(options.CodeModel))
|
.setCodeModel(unwrap(options.CodeModel))
|
||||||
.setTargetOptions(targetOptions);
|
.setTargetOptions(targetOptions);
|
||||||
|
if (options.MCJMM)
|
||||||
|
builder.setMCJITMemoryManager(unwrap(options.MCJMM));
|
||||||
if (ExecutionEngine *JIT = builder.create()) {
|
if (ExecutionEngine *JIT = builder.create()) {
|
||||||
*OutJIT = wrap(JIT);
|
*OutJIT = wrap(JIT);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -332,3 +333,110 @@ void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) {
|
||||||
|
|
||||||
return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global));
|
return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===-- Operations on memory managers -------------------------------------===*/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct SimpleBindingMMFunctions {
|
||||||
|
uint8_t *(*AllocateCodeSection)(void *Opaque,
|
||||||
|
uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID);
|
||||||
|
uint8_t *(*AllocateDataSection)(void *Opaque,
|
||||||
|
uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID, LLVMBool IsReadOnly);
|
||||||
|
LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg);
|
||||||
|
void (*Destroy)(void *Opaque);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SimpleBindingMemoryManager : public RTDyldMemoryManager {
|
||||||
|
public:
|
||||||
|
SimpleBindingMemoryManager(const SimpleBindingMMFunctions& Functions,
|
||||||
|
void *Opaque);
|
||||||
|
virtual ~SimpleBindingMemoryManager();
|
||||||
|
|
||||||
|
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID);
|
||||||
|
|
||||||
|
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID,
|
||||||
|
bool isReadOnly);
|
||||||
|
|
||||||
|
virtual bool finalizeMemory(std::string *ErrMsg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SimpleBindingMMFunctions Functions;
|
||||||
|
void *Opaque;
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleBindingMemoryManager::SimpleBindingMemoryManager(
|
||||||
|
const SimpleBindingMMFunctions& Functions,
|
||||||
|
void *Opaque)
|
||||||
|
: Functions(Functions), Opaque(Opaque) {
|
||||||
|
assert(Functions.AllocateCodeSection &&
|
||||||
|
"No AllocateCodeSection function provided!");
|
||||||
|
assert(Functions.AllocateDataSection &&
|
||||||
|
"No AllocateDataSection function provided!");
|
||||||
|
assert(Functions.FinalizeMemory &&
|
||||||
|
"No FinalizeMemory function provided!");
|
||||||
|
assert(Functions.Destroy &&
|
||||||
|
"No Destroy function provided!");
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleBindingMemoryManager::~SimpleBindingMemoryManager() {
|
||||||
|
Functions.Destroy(Opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *SimpleBindingMemoryManager::allocateCodeSection(
|
||||||
|
uintptr_t Size, unsigned Alignment, unsigned SectionID) {
|
||||||
|
return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *SimpleBindingMemoryManager::allocateDataSection(
|
||||||
|
uintptr_t Size, unsigned Alignment, unsigned SectionID, bool isReadOnly) {
|
||||||
|
return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID,
|
||||||
|
isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
||||||
|
char *errMsgCString = 0;
|
||||||
|
bool result = Functions.FinalizeMemory(Opaque, &errMsgCString);
|
||||||
|
assert((result || !errMsgCString) &&
|
||||||
|
"Did not expect an error message if FinalizeMemory succeeded");
|
||||||
|
if (errMsgCString) {
|
||||||
|
if (ErrMsg)
|
||||||
|
*ErrMsg = errMsgCString;
|
||||||
|
free(errMsgCString);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager(
|
||||||
|
void *Opaque,
|
||||||
|
uint8_t *(*AllocateCodeSection)(void *Opaque,
|
||||||
|
uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID),
|
||||||
|
uint8_t *(*AllocateDataSection)(void *Opaque,
|
||||||
|
uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID, LLVMBool IsReadOnly),
|
||||||
|
LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg),
|
||||||
|
void (*Destroy)(void *Opaque)) {
|
||||||
|
|
||||||
|
if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory ||
|
||||||
|
!Destroy)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
SimpleBindingMMFunctions functions;
|
||||||
|
functions.AllocateCodeSection = AllocateCodeSection;
|
||||||
|
functions.AllocateDataSection = AllocateDataSection;
|
||||||
|
functions.FinalizeMemory = FinalizeMemory;
|
||||||
|
functions.Destroy = Destroy;
|
||||||
|
return wrap(new SimpleBindingMemoryManager(functions, Opaque));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM) {
|
||||||
|
delete unwrap(MM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,10 @@ void LLVMShutdown() {
|
||||||
|
|
||||||
/*===-- Error handling ----------------------------------------------------===*/
|
/*===-- Error handling ----------------------------------------------------===*/
|
||||||
|
|
||||||
|
char *LLVMCreateMessage(const char *Message) {
|
||||||
|
return strdup(Message);
|
||||||
|
}
|
||||||
|
|
||||||
void LLVMDisposeMessage(char *Message) {
|
void LLVMDisposeMessage(char *Message) {
|
||||||
free(Message);
|
free(Message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,46 @@
|
||||||
#include "llvm-c/ExecutionEngine.h"
|
#include "llvm-c/ExecutionEngine.h"
|
||||||
#include "llvm-c/Target.h"
|
#include "llvm-c/Target.h"
|
||||||
#include "llvm-c/Transforms/Scalar.h"
|
#include "llvm-c/Transforms/Scalar.h"
|
||||||
|
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||||
#include "llvm/Support/Host.h"
|
#include "llvm/Support/Host.h"
|
||||||
#include "MCJITTestAPICommon.h"
|
#include "MCJITTestAPICommon.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
static bool didCallAllocateCodeSection;
|
||||||
|
|
||||||
|
static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
|
||||||
|
unsigned alignment,
|
||||||
|
unsigned sectionID) {
|
||||||
|
didCallAllocateCodeSection = true;
|
||||||
|
return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
|
||||||
|
size, alignment, sectionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
|
||||||
|
unsigned alignment,
|
||||||
|
unsigned sectionID,
|
||||||
|
LLVMBool isReadOnly) {
|
||||||
|
return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
|
||||||
|
size, alignment, sectionID, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
|
||||||
|
std::string errMsgString;
|
||||||
|
bool result =
|
||||||
|
static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
|
||||||
|
if (result) {
|
||||||
|
*errMsg = LLVMCreateMessage(errMsgString.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void roundTripDestroy(void *object) {
|
||||||
|
delete static_cast<SectionMemoryManager*>(object);
|
||||||
|
}
|
||||||
|
|
||||||
class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
|
class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
|
||||||
protected:
|
protected:
|
||||||
MCJITCAPITest() {
|
MCJITCAPITest() {
|
||||||
|
@ -46,60 +80,113 @@ protected:
|
||||||
// that they will fail the MCJIT C API tests.
|
// that they will fail the MCJIT C API tests.
|
||||||
UnsupportedOSs.push_back(Triple::Cygwin);
|
UnsupportedOSs.push_back(Triple::Cygwin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void SetUp() {
|
||||||
|
didCallAllocateCodeSection = false;
|
||||||
|
Module = 0;
|
||||||
|
Function = 0;
|
||||||
|
Engine = 0;
|
||||||
|
Error = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TearDown() {
|
||||||
|
if (Engine)
|
||||||
|
LLVMDisposeExecutionEngine(Engine);
|
||||||
|
else if (Module)
|
||||||
|
LLVMDisposeModule(Module);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildSimpleFunction() {
|
||||||
|
Module = LLVMModuleCreateWithName("simple_module");
|
||||||
|
|
||||||
|
LLVMSetTarget(Module, HostTriple.c_str());
|
||||||
|
|
||||||
|
Function = LLVMAddFunction(
|
||||||
|
Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
|
||||||
|
LLVMSetFunctionCallConv(Function, LLVMCCallConv);
|
||||||
|
|
||||||
|
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
|
||||||
|
LLVMBuilderRef builder = LLVMCreateBuilder();
|
||||||
|
LLVMPositionBuilderAtEnd(builder, entry);
|
||||||
|
LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
|
||||||
|
|
||||||
|
LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
|
||||||
|
LLVMDisposeMessage(Error);
|
||||||
|
|
||||||
|
LLVMDisposeBuilder(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildMCJITOptions() {
|
||||||
|
LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
|
||||||
|
Options.OptLevel = 2;
|
||||||
|
|
||||||
|
// Just ensure that this field still exists.
|
||||||
|
Options.NoFramePointerElim = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void useRoundTripSectionMemoryManager() {
|
||||||
|
Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
|
||||||
|
new SectionMemoryManager(),
|
||||||
|
roundTripAllocateCodeSection,
|
||||||
|
roundTripAllocateDataSection,
|
||||||
|
roundTripFinalizeMemory,
|
||||||
|
roundTripDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildMCJITEngine() {
|
||||||
|
ASSERT_EQ(
|
||||||
|
0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
|
||||||
|
sizeof(Options), &Error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildAndRunPasses() {
|
||||||
|
LLVMPassManagerRef pass = LLVMCreatePassManager();
|
||||||
|
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
|
||||||
|
LLVMAddConstantPropagationPass(pass);
|
||||||
|
LLVMAddInstructionCombiningPass(pass);
|
||||||
|
LLVMRunPassManager(pass, Module);
|
||||||
|
LLVMDisposePassManager(pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMModuleRef Module;
|
||||||
|
LLVMValueRef Function;
|
||||||
|
LLVMMCJITCompilerOptions Options;
|
||||||
|
LLVMExecutionEngineRef Engine;
|
||||||
|
char *Error;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(MCJITCAPITest, simple_function) {
|
TEST_F(MCJITCAPITest, simple_function) {
|
||||||
SKIP_UNSUPPORTED_PLATFORM;
|
SKIP_UNSUPPORTED_PLATFORM;
|
||||||
|
|
||||||
char *error = 0;
|
buildSimpleFunction();
|
||||||
|
buildMCJITOptions();
|
||||||
// Creates a function that returns 42, compiles it, and runs it.
|
buildMCJITEngine();
|
||||||
|
buildAndRunPasses();
|
||||||
LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
|
|
||||||
|
|
||||||
LLVMSetTarget(module, HostTriple.c_str());
|
|
||||||
|
|
||||||
LLVMValueRef function = LLVMAddFunction(
|
|
||||||
module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
|
|
||||||
LLVMSetFunctionCallConv(function, LLVMCCallConv);
|
|
||||||
|
|
||||||
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
|
|
||||||
LLVMBuilderRef builder = LLVMCreateBuilder();
|
|
||||||
LLVMPositionBuilderAtEnd(builder, entry);
|
|
||||||
LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
|
|
||||||
|
|
||||||
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
|
|
||||||
LLVMDisposeMessage(error);
|
|
||||||
|
|
||||||
LLVMDisposeBuilder(builder);
|
|
||||||
|
|
||||||
LLVMMCJITCompilerOptions options;
|
|
||||||
LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
|
|
||||||
options.OptLevel = 2;
|
|
||||||
|
|
||||||
// Just ensure that this field still exists.
|
|
||||||
options.NoFramePointerElim = false;
|
|
||||||
|
|
||||||
LLVMExecutionEngineRef engine;
|
|
||||||
ASSERT_EQ(
|
|
||||||
0, LLVMCreateMCJITCompilerForModule(&engine, module, &options,
|
|
||||||
sizeof(options), &error));
|
|
||||||
|
|
||||||
LLVMPassManagerRef pass = LLVMCreatePassManager();
|
|
||||||
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
|
|
||||||
LLVMAddConstantPropagationPass(pass);
|
|
||||||
LLVMAddInstructionCombiningPass(pass);
|
|
||||||
LLVMRunPassManager(pass, module);
|
|
||||||
LLVMDisposePassManager(pass);
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
void *raw;
|
void *raw;
|
||||||
int (*usable)();
|
int (*usable)();
|
||||||
} functionPointer;
|
} functionPointer;
|
||||||
functionPointer.raw = LLVMGetPointerToGlobal(engine, function);
|
functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
|
||||||
|
|
||||||
EXPECT_EQ(42, functionPointer.usable());
|
EXPECT_EQ(42, functionPointer.usable());
|
||||||
|
|
||||||
LLVMDisposeExecutionEngine(engine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MCJITCAPITest, custom_memory_manager) {
|
||||||
|
SKIP_UNSUPPORTED_PLATFORM;
|
||||||
|
|
||||||
|
buildSimpleFunction();
|
||||||
|
buildMCJITOptions();
|
||||||
|
useRoundTripSectionMemoryManager();
|
||||||
|
buildMCJITEngine();
|
||||||
|
buildAndRunPasses();
|
||||||
|
|
||||||
|
union {
|
||||||
|
void *raw;
|
||||||
|
int (*usable)();
|
||||||
|
} functionPointer;
|
||||||
|
functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
|
||||||
|
|
||||||
|
EXPECT_EQ(42, functionPointer.usable());
|
||||||
|
EXPECT_TRUE(didCallAllocateCodeSection);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue