mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-30 23:21:04 +00:00
Roll out r182407 and r182408 because they broke builds.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182409 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
52755c472a
commit
1441bf7a41
@ -411,7 +411,6 @@ void LLVMShutdown();
|
|||||||
|
|
||||||
/*===-- Error handling ----------------------------------------------------===*/
|
/*===-- Error handling ----------------------------------------------------===*/
|
||||||
|
|
||||||
char *LLVMCreateMessage(const char *Message);
|
|
||||||
void LLVMDisposeMessage(char *Message);
|
void LLVMDisposeMessage(char *Message);
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,14 +40,12 @@ 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 --------------------------------------===*/
|
||||||
@ -169,32 +167,6 @@ 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Interface of the runtime dynamic memory manager base class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
|
|
||||||
#define LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
|
|
||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
|
||||||
#include "llvm/Support/CBindingWrapping.h"
|
|
||||||
#include "llvm/Support/Memory.h"
|
|
||||||
#include "llvm-c/ExecutionEngine.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
// RuntimeDyld clients often want to handle the memory management of
|
|
||||||
// what gets placed where. For JIT clients, this is the subset of
|
|
||||||
// JITMemoryManager required for dynamic loading of binaries.
|
|
||||||
//
|
|
||||||
// FIXME: As the RuntimeDyld fills out, additional routines will be needed
|
|
||||||
// for the varying types of objects to be allocated.
|
|
||||||
class RTDyldMemoryManager {
|
|
||||||
RTDyldMemoryManager(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
|
|
||||||
void operator=(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
|
|
||||||
public:
|
|
||||||
RTDyldMemoryManager() {}
|
|
||||||
virtual ~RTDyldMemoryManager();
|
|
||||||
|
|
||||||
/// Allocate a memory block of (at least) the given size suitable for
|
|
||||||
/// executable code. The SectionID is a unique identifier assigned by the JIT
|
|
||||||
/// engine, and optionally recorded by the memory manager to access a loaded
|
|
||||||
/// section.
|
|
||||||
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
|
||||||
unsigned SectionID) = 0;
|
|
||||||
|
|
||||||
/// Allocate a memory block of (at least) the given size suitable for data.
|
|
||||||
/// The SectionID is a unique identifier assigned by the JIT engine, and
|
|
||||||
/// optionally recorded by the memory manager to access a loaded section.
|
|
||||||
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
|
||||||
unsigned SectionID, bool IsReadOnly) = 0;
|
|
||||||
|
|
||||||
/// Register the EH frames with the runtime so that c++ exceptions work.
|
|
||||||
virtual void registerEHFrames(StringRef SectionData);
|
|
||||||
|
|
||||||
/// This method returns the address of the specified function. As such it is
|
|
||||||
/// only useful for resolving library symbols, not code generated symbols.
|
|
||||||
///
|
|
||||||
/// If \p AbortOnFailure is false and no function with the given name is
|
|
||||||
/// found, this function returns a null pointer. Otherwise, it prints a
|
|
||||||
/// message to stderr and aborts.
|
|
||||||
virtual void *getPointerToNamedFunction(const std::string &Name,
|
|
||||||
bool AbortOnFailure = true);
|
|
||||||
|
|
||||||
/// This method is called when object loading is complete and section page
|
|
||||||
/// permissions can be applied. It is up to the memory manager implementation
|
|
||||||
/// to decide whether or not to act on this method. The memory manager will
|
|
||||||
/// typically allocate all sections as read-write and then apply specific
|
|
||||||
/// permissions when this method is called. Code sections cannot be executed
|
|
||||||
/// until this function has been called. In addition, any cache coherency
|
|
||||||
/// operations needed to reliably use the memory are also performed.
|
|
||||||
///
|
|
||||||
/// Returns true if an error occurred, false otherwise.
|
|
||||||
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
|
|
||||||
|
|
||||||
#endif // LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
|
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ExecutionEngine/ObjectBuffer.h"
|
#include "llvm/ExecutionEngine/ObjectBuffer.h"
|
||||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
|
||||||
#include "llvm/Support/Memory.h"
|
#include "llvm/Support/Memory.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -24,6 +23,58 @@ namespace llvm {
|
|||||||
class RuntimeDyldImpl;
|
class RuntimeDyldImpl;
|
||||||
class ObjectImage;
|
class ObjectImage;
|
||||||
|
|
||||||
|
// RuntimeDyld clients often want to handle the memory management of
|
||||||
|
// what gets placed where. For JIT clients, this is the subset of
|
||||||
|
// JITMemoryManager required for dynamic loading of binaries.
|
||||||
|
//
|
||||||
|
// FIXME: As the RuntimeDyld fills out, additional routines will be needed
|
||||||
|
// for the varying types of objects to be allocated.
|
||||||
|
class RTDyldMemoryManager {
|
||||||
|
RTDyldMemoryManager(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
|
||||||
|
void operator=(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
|
||||||
|
public:
|
||||||
|
RTDyldMemoryManager() {}
|
||||||
|
virtual ~RTDyldMemoryManager();
|
||||||
|
|
||||||
|
/// Allocate a memory block of (at least) the given size suitable for
|
||||||
|
/// executable code. The SectionID is a unique identifier assigned by the JIT
|
||||||
|
/// engine, and optionally recorded by the memory manager to access a loaded
|
||||||
|
/// section.
|
||||||
|
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID) = 0;
|
||||||
|
|
||||||
|
/// Allocate a memory block of (at least) the given size suitable for data.
|
||||||
|
/// The SectionID is a unique identifier assigned by the JIT engine, and
|
||||||
|
/// optionally recorded by the memory manager to access a loaded section.
|
||||||
|
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||||
|
unsigned SectionID, bool IsReadOnly) = 0;
|
||||||
|
|
||||||
|
/// This method returns the address of the specified function. As such it is
|
||||||
|
/// only useful for resolving library symbols, not code generated symbols.
|
||||||
|
///
|
||||||
|
/// If AbortOnFailure is false and no function with the given name is
|
||||||
|
/// found, this function returns a null pointer. Otherwise, it prints a
|
||||||
|
/// message to stderr and aborts.
|
||||||
|
virtual void *getPointerToNamedFunction(const std::string &Name,
|
||||||
|
bool AbortOnFailure = true) = 0;
|
||||||
|
|
||||||
|
/// This method is called when object loading is complete and section page
|
||||||
|
/// permissions can be applied. It is up to the memory manager implementation
|
||||||
|
/// to decide whether or not to act on this method. The memory manager will
|
||||||
|
/// typically allocate all sections as read-write and then apply specific
|
||||||
|
/// permissions when this method is called. Code sections cannot be executed
|
||||||
|
/// until this function has been called. In addition, any cache coherency
|
||||||
|
/// operations needed to reliably use the memory are also performed.
|
||||||
|
///
|
||||||
|
/// Returns true if an error occurred, false otherwise.
|
||||||
|
virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0;
|
||||||
|
|
||||||
|
/// Register the EH frames with the runtime so that c++ exceptions work. The
|
||||||
|
/// default implementation does nothing. Look at SectionMemoryManager for one
|
||||||
|
/// that uses __register_frame.
|
||||||
|
virtual void registerEHFrames(StringRef SectionData);
|
||||||
|
};
|
||||||
|
|
||||||
class RuntimeDyld {
|
class RuntimeDyld {
|
||||||
RuntimeDyld(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
|
RuntimeDyld(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
|
||||||
void operator=(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
|
void operator=(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
|
||||||
|
@ -73,6 +73,17 @@ public:
|
|||||||
/// \returns true if an error occurred, false otherwise.
|
/// \returns true if an error occurred, false otherwise.
|
||||||
virtual bool finalizeMemory(std::string *ErrMsg = 0);
|
virtual bool finalizeMemory(std::string *ErrMsg = 0);
|
||||||
|
|
||||||
|
void registerEHFrames(StringRef SectionData);
|
||||||
|
|
||||||
|
/// This method returns the address of the specified function. As such it is
|
||||||
|
/// only useful for resolving library symbols, not code generated symbols.
|
||||||
|
///
|
||||||
|
/// If \p AbortOnFailure is false and no function with the given name is
|
||||||
|
/// found, this function returns a null pointer. Otherwise, it prints a
|
||||||
|
/// message to stderr and aborts.
|
||||||
|
virtual void *getPointerToNamedFunction(const std::string &Name,
|
||||||
|
bool AbortOnFailure = true);
|
||||||
|
|
||||||
/// \brief Invalidate instruction cache for code sections.
|
/// \brief Invalidate instruction cache for code sections.
|
||||||
///
|
///
|
||||||
/// Some platforms with separate data cache and instruction cache require
|
/// Some platforms with separate data cache and instruction cache require
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
add_llvm_library(LLVMExecutionEngine
|
add_llvm_library(LLVMExecutionEngine
|
||||||
ExecutionEngine.cpp
|
ExecutionEngine.cpp
|
||||||
ExecutionEngineBindings.cpp
|
ExecutionEngineBindings.cpp
|
||||||
RTDyldMemoryManager.cpp
|
|
||||||
TargetSelect.cpp
|
TargetSelect.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#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"
|
||||||
@ -158,8 +157,10 @@ LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
|
|||||||
void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions,
|
void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions,
|
||||||
size_t SizeOfPassedOptions) {
|
size_t SizeOfPassedOptions) {
|
||||||
LLVMMCJITCompilerOptions options;
|
LLVMMCJITCompilerOptions options;
|
||||||
memset(&options, 0, sizeof(options)); // Most fields are zero by default.
|
options.OptLevel = 0;
|
||||||
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));
|
||||||
@ -198,8 +199,6 @@ 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;
|
||||||
@ -333,110 +332,3 @@ 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "llvm/Config/config.h"
|
#include "llvm/Config/config.h"
|
||||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||||
|
#include "llvm/Support/DynamicLibrary.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -145,6 +146,38 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine whether we can register EH tables.
|
||||||
|
#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
|
||||||
|
!defined(__USING_SJLJ_EXCEPTIONS__))
|
||||||
|
#define HAVE_EHTABLE_SUPPORT 1
|
||||||
|
#else
|
||||||
|
#define HAVE_EHTABLE_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_EHTABLE_SUPPORT
|
||||||
|
extern "C" void __register_frame(void*);
|
||||||
|
|
||||||
|
static const char *processFDE(const char *Entry) {
|
||||||
|
const char *P = Entry;
|
||||||
|
uint32_t Length = *((uint32_t*)P);
|
||||||
|
P += 4;
|
||||||
|
uint32_t Offset = *((uint32_t*)P);
|
||||||
|
if (Offset != 0)
|
||||||
|
__register_frame((void*)Entry);
|
||||||
|
return P + Length;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SectionMemoryManager::registerEHFrames(StringRef SectionData) {
|
||||||
|
#if HAVE_EHTABLE_SUPPORT
|
||||||
|
const char *P = SectionData.data();
|
||||||
|
const char *End = SectionData.data() + SectionData.size();
|
||||||
|
do {
|
||||||
|
P = processFDE(P);
|
||||||
|
} while(P != End);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
|
error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
|
||||||
unsigned Permissions) {
|
unsigned Permissions) {
|
||||||
|
|
||||||
@ -166,6 +199,57 @@ void SectionMemoryManager::invalidateInstructionCache() {
|
|||||||
CodeMem.AllocatedMem[i].size());
|
CodeMem.AllocatedMem[i].size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int jit_noop() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name,
|
||||||
|
bool AbortOnFailure) {
|
||||||
|
#if defined(__linux__)
|
||||||
|
//===--------------------------------------------------------------------===//
|
||||||
|
// Function stubs that are invoked instead of certain library calls
|
||||||
|
//
|
||||||
|
// Force the following functions to be linked in to anything that uses the
|
||||||
|
// JIT. This is a hack designed to work around the all-too-clever Glibc
|
||||||
|
// strategy of making these functions work differently when inlined vs. when
|
||||||
|
// not inlined, and hiding their real definitions in a separate archive file
|
||||||
|
// that the dynamic linker can't see. For more info, search for
|
||||||
|
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
|
||||||
|
if (Name == "stat") return (void*)(intptr_t)&stat;
|
||||||
|
if (Name == "fstat") return (void*)(intptr_t)&fstat;
|
||||||
|
if (Name == "lstat") return (void*)(intptr_t)&lstat;
|
||||||
|
if (Name == "stat64") return (void*)(intptr_t)&stat64;
|
||||||
|
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
|
||||||
|
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
|
||||||
|
if (Name == "atexit") return (void*)(intptr_t)&atexit;
|
||||||
|
if (Name == "mknod") return (void*)(intptr_t)&mknod;
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
// We should not invoke parent's ctors/dtors from generated main()!
|
||||||
|
// On Mingw and Cygwin, the symbol __main is resolved to
|
||||||
|
// callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
|
||||||
|
// (and register wrong callee's dtors with atexit(3)).
|
||||||
|
// We expect ExecutionEngine::runStaticConstructorsDestructors()
|
||||||
|
// is called before ExecutionEngine::runFunctionAsMain() is called.
|
||||||
|
if (Name == "__main") return (void*)(intptr_t)&jit_noop;
|
||||||
|
|
||||||
|
const char *NameStr = Name.c_str();
|
||||||
|
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
|
||||||
|
if (Ptr) return Ptr;
|
||||||
|
|
||||||
|
// If it wasn't found and if it starts with an underscore ('_') character,
|
||||||
|
// try again without the underscore.
|
||||||
|
if (NameStr[0] == '_') {
|
||||||
|
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
|
||||||
|
if (Ptr) return Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AbortOnFailure)
|
||||||
|
report_fatal_error("Program used external function '" + Name +
|
||||||
|
"' which could not be resolved!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
SectionMemoryManager::~SectionMemoryManager() {
|
SectionMemoryManager::~SectionMemoryManager() {
|
||||||
for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
|
for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
|
||||||
sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);
|
sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Implementation of the runtime dynamic memory manager base class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
|
||||||
#include "llvm/Support/DynamicLibrary.h"
|
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
RTDyldMemoryManager::~RTDyldMemoryManager() {}
|
|
||||||
|
|
||||||
// Determine whether we can register EH tables.
|
|
||||||
#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
|
|
||||||
!defined(__USING_SJLJ_EXCEPTIONS__))
|
|
||||||
#define HAVE_EHTABLE_SUPPORT 1
|
|
||||||
#else
|
|
||||||
#define HAVE_EHTABLE_SUPPORT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if HAVE_EHTABLE_SUPPORT
|
|
||||||
extern "C" void __register_frame(void*);
|
|
||||||
|
|
||||||
static const char *processFDE(const char *Entry) {
|
|
||||||
const char *P = Entry;
|
|
||||||
uint32_t Length = *((uint32_t*)P);
|
|
||||||
P += 4;
|
|
||||||
uint32_t Offset = *((uint32_t*)P);
|
|
||||||
if (Offset != 0)
|
|
||||||
__register_frame((void*)Entry);
|
|
||||||
return P + Length;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {
|
|
||||||
#if HAVE_EHTABLE_SUPPORT
|
|
||||||
const char *P = SectionData.data();
|
|
||||||
const char *End = SectionData.data() + SectionData.size();
|
|
||||||
do {
|
|
||||||
P = processFDE(P);
|
|
||||||
} while(P != End);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jit_noop() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
|
|
||||||
bool AbortOnFailure) {
|
|
||||||
#if defined(__linux__)
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Function stubs that are invoked instead of certain library calls
|
|
||||||
//
|
|
||||||
// Force the following functions to be linked in to anything that uses the
|
|
||||||
// JIT. This is a hack designed to work around the all-too-clever Glibc
|
|
||||||
// strategy of making these functions work differently when inlined vs. when
|
|
||||||
// not inlined, and hiding their real definitions in a separate archive file
|
|
||||||
// that the dynamic linker can't see. For more info, search for
|
|
||||||
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
|
|
||||||
if (Name == "stat") return (void*)(intptr_t)&stat;
|
|
||||||
if (Name == "fstat") return (void*)(intptr_t)&fstat;
|
|
||||||
if (Name == "lstat") return (void*)(intptr_t)&lstat;
|
|
||||||
if (Name == "stat64") return (void*)(intptr_t)&stat64;
|
|
||||||
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
|
|
||||||
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
|
|
||||||
if (Name == "atexit") return (void*)(intptr_t)&atexit;
|
|
||||||
if (Name == "mknod") return (void*)(intptr_t)&mknod;
|
|
||||||
#endif // __linux__
|
|
||||||
|
|
||||||
// We should not invoke parent's ctors/dtors from generated main()!
|
|
||||||
// On Mingw and Cygwin, the symbol __main is resolved to
|
|
||||||
// callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
|
|
||||||
// (and register wrong callee's dtors with atexit(3)).
|
|
||||||
// We expect ExecutionEngine::runStaticConstructorsDestructors()
|
|
||||||
// is called before ExecutionEngine::runFunctionAsMain() is called.
|
|
||||||
if (Name == "__main") return (void*)(intptr_t)&jit_noop;
|
|
||||||
|
|
||||||
const char *NameStr = Name.c_str();
|
|
||||||
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
|
|
||||||
if (Ptr) return Ptr;
|
|
||||||
|
|
||||||
// If it wasn't found and if it starts with an underscore ('_') character,
|
|
||||||
// try again without the underscore.
|
|
||||||
if (NameStr[0] == '_') {
|
|
||||||
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
|
|
||||||
if (Ptr) return Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AbortOnFailure)
|
|
||||||
report_fatal_error("Program used external function '" + Name +
|
|
||||||
"' which could not be resolved!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace llvm
|
|
@ -24,6 +24,8 @@ using namespace llvm;
|
|||||||
using namespace llvm::object;
|
using namespace llvm::object;
|
||||||
|
|
||||||
// Empty out-of-line virtual destructor as the key function.
|
// Empty out-of-line virtual destructor as the key function.
|
||||||
|
RTDyldMemoryManager::~RTDyldMemoryManager() {}
|
||||||
|
void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {}
|
||||||
RuntimeDyldImpl::~RuntimeDyldImpl() {}
|
RuntimeDyldImpl::~RuntimeDyldImpl() {}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -58,10 +58,6 @@ 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,46 +17,12 @@
|
|||||||
#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() {
|
||||||
@ -80,113 +46,60 @@ 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;
|
||||||
|
|
||||||
buildSimpleFunction();
|
char *error = 0;
|
||||||
buildMCJITOptions();
|
|
||||||
buildMCJITEngine();
|
// Creates a function that returns 42, compiles it, and runs it.
|
||||||
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
Block a user