Cleanup the JIT as per PR176. This renames the VM class to JIT, and merges the

VM.cpp and JIT.cpp files into JIT.cpp.  This also splits some nasty code out
into TargetSelect.cpp so that people hopefully won't notice it.  :)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10544 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2003-12-20 01:46:27 +00:00
parent 61612df9cb
commit 4d326fa9be
7 changed files with 217 additions and 315 deletions

View File

@ -15,7 +15,7 @@
//
//===----------------------------------------------------------------------===//
#include "VM.h"
#include "JIT.h"
#include "Support/DynamicLinker.h"
#include <iostream>
using namespace llvm;
@ -28,7 +28,7 @@ static std::vector<void (*)()> AtExitHandlers;
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
void VM::runAtExitHandlers() {
void JIT::runAtExitHandlers() {
while (!AtExitHandlers.empty()) {
void (*Fn)() = AtExitHandlers.back();
AtExitHandlers.pop_back();
@ -45,7 +45,7 @@ static void NoopFn() {}
// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
VM::runAtExitHandlers(); // Run atexit handlers...
JIT::runAtExitHandlers(); // Run atexit handlers...
exit(Status);
}
@ -61,7 +61,7 @@ static int jit_atexit(void (*Fn)(void)) {
/// function by using the dynamic loader interface. As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
void *VM::getPointerToNamedFunction(const std::string &Name) {
void *JIT::getPointerToNamedFunction(const std::string &Name) {
// Check to see if this is one of the functions we want to intercept...
if (Name == "exit") return (void*)&jit_exit;
if (Name == "atexit") return (void*)&jit_atexit;

View File

@ -1,4 +1,4 @@
//===-- JIT.cpp - LLVM Just-In-Time Compiler ------------------------------===//
//===-- JIT.cpp - LLVM Just in Time Compiler ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@ -7,102 +7,50 @@
//
//===----------------------------------------------------------------------===//
//
// This file implements the top-level support for creating a Just-In-Time
// compiler for the current architecture.
// This tool implements a just-in-time compiler for LLVM, allowing direct
// execution of LLVM bytecode in an efficient manner.
//
//===----------------------------------------------------------------------===//
#include "VM.h"
#include "llvm/Module.h"
#include "JIT.h"
#include "llvm/Function.h"
#include "llvm/ModuleProvider.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "Support/CommandLine.h"
#include "llvm/Target/TargetJITInfo.h"
using namespace llvm;
#if !defined(ENABLE_X86_JIT) && !defined(ENABLE_SPARC_JIT)
#define NO_JITS_ENABLED
#endif
namespace {
enum ArchName { x86, Sparc };
#ifndef NO_JITS_ENABLED
cl::opt<ArchName>
Arch("march", cl::desc("Architecture to JIT to:"), cl::Prefix,
cl::values(
#ifdef ENABLE_X86_JIT
clEnumVal(x86, " IA-32 (Pentium and above)"),
#endif
#ifdef ENABLE_SPARC_JIT
clEnumValN(Sparc, "sparc", " Sparc-V9"),
#endif
0),
#if defined(ENABLE_X86_JIT)
cl::init(x86)
#elif defined(ENABLE_SPARC_JIT)
cl::init(Sparc)
#endif
);
#endif /* NO_JITS_ENABLED */
}
/// create - Create an return a new JIT compiler if there is one available
/// for the current target. Otherwise, return null.
///
ExecutionEngine *VM::create(ModuleProvider *MP) {
TargetMachine* (*TargetMachineAllocator)(const Module &) = 0;
// Allow a command-line switch to override what *should* be the default target
// machine for this platform. This allows for debugging a Sparc JIT on X86 --
// our X86 machines are much faster at recompiling LLVM and linking LLI.
#ifndef NO_JITS_ENABLED
switch (Arch) {
#ifdef ENABLE_X86_JIT
case x86:
TargetMachineAllocator = allocateX86TargetMachine;
break;
#endif
#ifdef ENABLE_SPARC_JIT
case Sparc:
TargetMachineAllocator = allocateSparcTargetMachine;
break;
#endif
default:
assert(0 && "-march flag not supported on this host!");
}
#else
return 0;
#endif
// Allocate a target...
TargetMachine *Target = TargetMachineAllocator(*MP->getModule());
assert(Target && "Could not allocate target machine!");
// If the target supports JIT code generation, return a new JIT now.
if (TargetJITInfo *TJ = Target->getJITInfo())
return new VM(MP, *Target, *TJ);
return 0;
}
VM::VM(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
: ExecutionEngine(MP), TM(tm), TJI(tji), PM(MP) {
setTargetData(TM.getTargetData());
// Initialize MCE
MCE = createEmitter(*this);
setupPassManager();
// Compile LLVM Code down to machine code in the intermediate representation
TJI.addPassesToJITCompile(PM);
// Turn the machine code intermediate representation into bytes in memory that
// may be executed.
if (TM.addPassesToEmitMachineCode(PM, *MCE)) {
std::cerr << "lli: target '" << TM.getName()
<< "' doesn't support machine code emission!\n";
abort();
}
emitGlobals();
}
JIT::~JIT() {
delete MCE;
delete &TM;
}
/// run - Start execution with the specified function and arguments.
///
GenericValue VM::run(Function *F, const std::vector<GenericValue> &ArgValues)
{
GenericValue JIT::run(Function *F, const std::vector<GenericValue> &ArgValues) {
assert (F && "Function *F was null at entry to run()");
int (*PF)(int, char **, const char **) =
@ -120,3 +68,74 @@ GenericValue VM::run(Function *F, const std::vector<GenericValue> &ArgValues)
rv.IntVal = ExitCode;
return rv;
}
/// runJITOnFunction - Run the FunctionPassManager full of
/// just-in-time compilation passes on F, hopefully filling in
/// GlobalAddress[F] with the address of F's machine code.
///
void JIT::runJITOnFunction(Function *F) {
static bool isAlreadyCodeGenerating = false;
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
// JIT the function
isAlreadyCodeGenerating = true;
PM.run(*F);
isAlreadyCodeGenerating = false;
}
/// getPointerToFunction - This method is used to get the address of the
/// specified function, compiling it if neccesary.
///
void *JIT::getPointerToFunction(Function *F) {
void *&Addr = GlobalAddress[F]; // Check if function already code gen'd
if (Addr) return Addr;
// Make sure we read in the function if it exists in this Module
MP->materializeFunction(F);
if (F->isExternal())
return Addr = getPointerToNamedFunction(F->getName());
runJITOnFunction(F);
assert(Addr && "Code generation didn't add function to GlobalAddress table!");
return Addr;
}
// getPointerToFunctionOrStub - If the specified function has been
// code-gen'd, return a pointer to the function. If not, compile it, or use
// a stub to implement lazy compilation if available.
//
void *JIT::getPointerToFunctionOrStub(Function *F) {
// If we have already code generated the function, just return the address.
std::map<const GlobalValue*, void *>::iterator I = GlobalAddress.find(F);
if (I != GlobalAddress.end()) return I->second;
// If the target supports "stubs" for functions, get a stub now.
if (void *Ptr = TJI.getJITStubForFunction(F, *MCE))
return Ptr;
// Otherwise, if the target doesn't support it, just codegen the function.
return getPointerToFunction(F);
}
/// recompileAndRelinkFunction - This method is used to force a function
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
/// just like JIT::getPointerToFunction().
///
void *JIT::recompileAndRelinkFunction(Function *F) {
void *&Addr = GlobalAddress[F]; // Check if function already code gen'd
// If it's not already compiled (this is kind of weird) there is no
// reason to patch it up.
if (!Addr) { return getPointerToFunction (F); }
void *OldAddr = Addr;
Addr = 0;
MachineFunction::destruct(F);
runJITOnFunction(F);
assert(Addr && "Code generation didn't add function to GlobalAddress table!");
TJI.replaceMachineCodeForFunction(OldAddr, Addr);
return Addr;
}

View File

@ -1,4 +1,4 @@
//===-- VM.h - Definitions for Virtual Machine ------------------*- C++ -*-===//
//===-- JIT.h - Class definition for the JIT --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines the top-level Virtual Machine data structure.
// This file defines the top-level JIT data structure.
//
//===----------------------------------------------------------------------===//
#ifndef VM_H
#define VM_H
#ifndef JIT_H
#define JIT_H
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/PassManager.h"
@ -27,16 +27,16 @@ class TargetMachine;
class TargetJITInfo;
class MachineCodeEmitter;
class VM : public ExecutionEngine {
class JIT : public ExecutionEngine {
TargetMachine &TM; // The current target we are compiling to
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
FunctionPassManager PM; // Passes to compile a function
MachineCodeEmitter *MCE; // MCE object
VM(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
public:
~VM();
~JIT();
/// create - Create an return a new JIT compiler if there is one available
/// for the current target. Otherwise, return null.
@ -79,13 +79,12 @@ public:
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
/// just like VM::getPointerToFunction().
/// just like JIT::getPointerToFunction().
///
void *recompileAndRelinkFunction(Function *F);
private:
static MachineCodeEmitter *createEmitter(VM &V);
void setupPassManager();
static MachineCodeEmitter *createEmitter(JIT &J);
void runJITOnFunction (Function *F);
};

View File

@ -16,7 +16,7 @@
#ifndef _POSIX_MAPPED_FILES
#define _POSIX_MAPPED_FILES
#endif
#include "VM.h"
#include "JIT.h"
#include "llvm/Constant.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
@ -31,7 +31,7 @@ using namespace llvm;
namespace {
Statistic<> NumBytes("jit", "Number of bytes of machine code compiled");
VM *TheVM = 0;
JIT *TheJIT = 0;
/// JITMemoryManager - Manage memory for the JIT code generation in a logical,
/// sane way. This splits a large block of MAP_NORESERVE'd memory into two
@ -142,7 +142,7 @@ namespace {
// constant pool.
std::vector<void*> ConstantPoolAddresses;
public:
Emitter(VM &vm) { TheVM = &vm; }
Emitter(JIT &jit) { TheJIT = &jit; }
virtual void startFunction(MachineFunction &F);
virtual void finishFunction(MachineFunction &F);
@ -166,13 +166,13 @@ namespace {
};
}
MachineCodeEmitter *VM::createEmitter(VM &V) {
return new Emitter(V);
MachineCodeEmitter *JIT::createEmitter(JIT &jit) {
return new Emitter(jit);
}
void Emitter::startFunction(MachineFunction &F) {
CurByte = CurBlock = MemMgr.startFunctionBody();
TheVM->addGlobalMapping(F.getFunction(), CurBlock);
TheJIT->addGlobalMapping(F.getFunction(), CurBlock);
}
void Emitter::finishFunction(MachineFunction &F) {
@ -197,8 +197,8 @@ void Emitter::emitConstantPool(MachineConstantPool *MCP) {
unsigned TotalSize = 0;
for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
const Type *Ty = Constants[i]->getType();
unsigned Size = TheVM->getTargetData().getTypeSize(Ty);
unsigned Alignment = TheVM->getTargetData().getTypeAlignment(Ty);
unsigned Size = TheJIT->getTargetData().getTypeSize(Ty);
unsigned Alignment = TheJIT->getTargetData().getTypeAlignment(Ty);
// Make sure to take into account the alignment requirements of the type.
TotalSize = (TotalSize + Alignment-1) & ~(Alignment-1);
@ -213,7 +213,7 @@ void Emitter::emitConstantPool(MachineConstantPool *MCP) {
// Actually output all of the constants, and remember their addresses.
for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
void *Addr = Pool + ConstantOffset[i];
TheVM->InitializeMemory(Constants[i], Addr);
TheJIT->InitializeMemory(Constants[i], Addr);
ConstantPoolAddresses.push_back(Addr);
}
}
@ -248,10 +248,10 @@ void Emitter::emitWord(unsigned W) {
uint64_t Emitter::getGlobalValueAddress(GlobalValue *V) {
// Try looking up the function to see if it is already compiled, if not return
// 0.
return (intptr_t)TheVM->getPointerToGlobalIfAvailable(V);
return (intptr_t)TheJIT->getPointerToGlobalIfAvailable(V);
}
uint64_t Emitter::getGlobalValueAddress(const std::string &Name) {
return (intptr_t)TheVM->getPointerToNamedFunction(Name);
return (intptr_t)TheJIT->getPointerToNamedFunction(Name);
}
// getConstantPoolEntryAddress - Return the address of the 'ConstantNum' entry
@ -272,19 +272,19 @@ uint64_t Emitter::getCurrentPCValue() {
}
uint64_t Emitter::forceCompilationOf(Function *F) {
return (intptr_t)TheVM->getPointerToFunction(F);
return (intptr_t)TheJIT->getPointerToFunction(F);
}
// getPointerToNamedFunction - This function is used as a global wrapper to
// VM::getPointerToNamedFunction for the purpose of resolving symbols when
// JIT::getPointerToNamedFunction for the purpose of resolving symbols when
// bugpoint is debugging the JIT. In that scenario, we are loading an .so and
// need to resolve function(s) that are being mis-codegenerated, so we need to
// resolve their addresses at runtime, and this is the way to do it.
extern "C" {
void *getPointerToNamedFunction(const char *Name) {
Module &M = TheVM->getModule();
Module &M = TheJIT->getModule();
if (Function *F = M.getNamedFunction(Name))
return TheVM->getPointerToFunction(F);
return TheVM->getPointerToNamedFunction(Name);
return TheJIT->getPointerToFunction(F);
return TheJIT->getPointerToNamedFunction(Name);
}
}

View File

@ -0,0 +1,92 @@
//===-- TargetSelect.cpp - Target Chooser Code ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the hideously gross code that is currently used to select
// a particular TargetMachine for the JIT to use. This should obviously be
// improved in the future, probably by having the TargetMachines register
// themselves with the runtime, and then have them choose themselves if they
// match the current machine.
//
//===----------------------------------------------------------------------===//
#include "JIT.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "Support/CommandLine.h"
using namespace llvm;
#if !defined(ENABLE_X86_JIT) && !defined(ENABLE_SPARC_JIT)
#define NO_JITS_ENABLED
#endif
namespace {
enum ArchName { x86, Sparc };
#ifndef NO_JITS_ENABLED
cl::opt<ArchName>
Arch("march", cl::desc("Architecture to JIT to:"), cl::Prefix,
cl::values(
#ifdef ENABLE_X86_JIT
clEnumVal(x86, " IA-32 (Pentium and above)"),
#endif
#ifdef ENABLE_SPARC_JIT
clEnumValN(Sparc, "sparc", " Sparc-V9"),
#endif
0),
#if defined(ENABLE_X86_JIT)
cl::init(x86)
#elif defined(ENABLE_SPARC_JIT)
cl::init(Sparc)
#endif
);
#endif /* NO_JITS_ENABLED */
}
/// create - Create an return a new JIT compiler if there is one available
/// for the current target. Otherwise, return null.
///
ExecutionEngine *JIT::create(ModuleProvider *MP) {
TargetMachine* (*TargetMachineAllocator)(const Module &) = 0;
// Allow a command-line switch to override what *should* be the default target
// machine for this platform. This allows for debugging a Sparc JIT on X86 --
// our X86 machines are much faster at recompiling LLVM and linking LLI.
#ifndef NO_JITS_ENABLED
switch (Arch) {
#ifdef ENABLE_X86_JIT
case x86:
TargetMachineAllocator = allocateX86TargetMachine;
break;
#endif
#ifdef ENABLE_SPARC_JIT
case Sparc:
TargetMachineAllocator = allocateSparcTargetMachine;
break;
#endif
default:
assert(0 && "-march flag not supported on this host!");
}
#else
return 0;
#endif
// Allocate a target...
TargetMachine *Target = TargetMachineAllocator(*MP->getModule());
assert(Target && "Could not allocate target machine!");
// If the target supports JIT code generation, return a new JIT now.
if (TargetJITInfo *TJ = Target->getJITInfo())
return new JIT(MP, *Target, *TJ);
return 0;
}

View File

@ -1,114 +0,0 @@
//===-- VM.cpp - LLVM Just in Time Compiler -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool implements a just-in-time compiler for LLVM, allowing direct
// execution of LLVM bytecode in an efficient manner.
//
//===----------------------------------------------------------------------===//
#include "VM.h"
#include "llvm/Function.h"
#include "llvm/ModuleProvider.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetJITInfo.h"
using namespace llvm;
VM::~VM() {
delete MCE;
delete &TM;
}
/// setupPassManager - Initialize the VM PassManager object with all of the
/// passes needed for the target to generate code.
///
void VM::setupPassManager() {
// Compile LLVM Code down to machine code in the intermediate representation
TJI.addPassesToJITCompile(PM);
// Turn the machine code intermediate representation into bytes in memory that
// may be executed.
if (TM.addPassesToEmitMachineCode(PM, *MCE)) {
std::cerr << "lli: target '" << TM.getName()
<< "' doesn't support machine code emission!\n";
abort();
}
}
/// runJITOnFunction - Run the FunctionPassManager full of
/// just-in-time compilation passes on F, hopefully filling in
/// GlobalAddress[F] with the address of F's machine code.
///
void VM::runJITOnFunction(Function *F) {
static bool isAlreadyCodeGenerating = false;
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
// JIT the function
isAlreadyCodeGenerating = true;
PM.run(*F);
isAlreadyCodeGenerating = false;
}
/// getPointerToFunction - This method is used to get the address of the
/// specified function, compiling it if neccesary.
///
void *VM::getPointerToFunction(Function *F) {
void *&Addr = GlobalAddress[F]; // Check if function already code gen'd
if (Addr) return Addr;
// Make sure we read in the function if it exists in this Module
MP->materializeFunction(F);
if (F->isExternal())
return Addr = getPointerToNamedFunction(F->getName());
runJITOnFunction(F);
assert(Addr && "Code generation didn't add function to GlobalAddress table!");
return Addr;
}
// getPointerToFunctionOrStub - If the specified function has been
// code-gen'd, return a pointer to the function. If not, compile it, or use
// a stub to implement lazy compilation if available.
//
void *VM::getPointerToFunctionOrStub(Function *F) {
// If we have already code generated the function, just return the address.
std::map<const GlobalValue*, void *>::iterator I = GlobalAddress.find(F);
if (I != GlobalAddress.end()) return I->second;
// If the target supports "stubs" for functions, get a stub now.
if (void *Ptr = TJI.getJITStubForFunction(F, *MCE))
return Ptr;
// Otherwise, if the target doesn't support it, just codegen the function.
return getPointerToFunction(F);
}
/// recompileAndRelinkFunction - This method is used to force a function
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
/// just like VM::getPointerToFunction().
///
void *VM::recompileAndRelinkFunction(Function *F) {
void *&Addr = GlobalAddress[F]; // Check if function already code gen'd
// If it's not already compiled (this is kind of weird) there is no
// reason to patch it up.
if (!Addr) { return getPointerToFunction (F); }
void *OldAddr = Addr;
Addr = 0;
MachineFunction::destruct(F);
runJITOnFunction(F);
assert(Addr && "Code generation didn't add function to GlobalAddress table!");
TJI.replaceMachineCodeForFunction(OldAddr, Addr);
return Addr;
}

View File

@ -1,94 +0,0 @@
//===-- VM.h - Definitions for Virtual Machine ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the top-level Virtual Machine data structure.
//
//===----------------------------------------------------------------------===//
#ifndef VM_H
#define VM_H
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/PassManager.h"
#include <map>
namespace llvm {
class Function;
class GlobalValue;
class Constant;
class TargetMachine;
class TargetJITInfo;
class MachineCodeEmitter;
class VM : public ExecutionEngine {
TargetMachine &TM; // The current target we are compiling to
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
FunctionPassManager PM; // Passes to compile a function
MachineCodeEmitter *MCE; // MCE object
VM(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
public:
~VM();
/// create - Create an return a new JIT compiler if there is one available
/// for the current target. Otherwise, return null.
///
static ExecutionEngine *create(ModuleProvider *MP);
/// run - Start execution with the specified function and arguments.
///
virtual GenericValue run(Function *F,
const std::vector<GenericValue> &ArgValues);
/// getPointerToNamedFunction - This method returns the address of the
/// specified function by using the dlsym function call. As such it is only
/// useful for resolving library symbols, not code generated symbols.
///
void *getPointerToNamedFunction(const std::string &Name);
// CompilationCallback - Invoked the first time that a call site is found,
// which causes lazy compilation of the target function.
//
static void CompilationCallback();
/// runAtExitHandlers - Before exiting the program, at_exit functions must be
/// called. This method calls them.
///
static void runAtExitHandlers();
/// getPointerToFunction - This returns the address of the specified function,
/// compiling it if necessary.
///
void *getPointerToFunction(Function *F);
/// getPointerToFunctionOrStub - If the specified function has been
/// code-gen'd, return a pointer to the function. If not, compile it, or use
/// a stub to implement lazy compilation if available.
///
void *getPointerToFunctionOrStub(Function *F);
/// recompileAndRelinkFunction - This method is used to force a function
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
/// just like VM::getPointerToFunction().
///
void *recompileAndRelinkFunction(Function *F);
private:
static MachineCodeEmitter *createEmitter(VM &V);
void setupPassManager();
void runJITOnFunction (Function *F);
};
} // End llvm namespace
#endif