diff options
| author | Chris Lattner <sabre@nondot.org> | 2002-12-24 00:01:05 +0000 | 
|---|---|---|
| committer | Chris Lattner <sabre@nondot.org> | 2002-12-24 00:01:05 +0000 | 
| commit | 996fe0102878d706d47a06bc78d21d1f38ed2aec (patch) | |
| tree | 8449f4d70e68c16bcb8a5b6ba2dfe8d01c6095b8 /llvm/lib/ExecutionEngine | |
| parent | a0d7b084ef7faab8739ef3e9186fdf9a94c3ed22 (diff) | |
| download | bcm5719-llvm-996fe0102878d706d47a06bc78d21d1f38ed2aec.tar.gz bcm5719-llvm-996fe0102878d706d47a06bc78d21d1f38ed2aec.zip  | |
Initial checkin of new LLI with JIT compiler
llvm-svn: 5126
Diffstat (limited to 'llvm/lib/ExecutionEngine')
| -rw-r--r-- | llvm/lib/ExecutionEngine/ExecutionEngine.cpp | 226 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp | 56 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/Interpreter/Makefile | 4 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/Callback.cpp | 62 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/Emitter.cpp | 107 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/GlobalVars.cpp | 0 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/JIT.cpp | 53 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/Makefile | 4 | ||||
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/VM.cpp | 84 | 
9 files changed, 596 insertions, 0 deletions
diff --git a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp new file mode 100644 index 00000000000..996afe475d4 --- /dev/null +++ b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp @@ -0,0 +1,226 @@ +//===-- ExecutionEngine.cpp - Common Implementation shared by EE's --------===// +//  +// This file defines the common interface used by the various execution engine +// subclasses. +// +//===----------------------------------------------------------------------===// + +#include "ExecutionEngine.h" +#include "GenericValue.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Constants.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetData.h" +#include "Support/Statistic.h" + +Statistic<> NumInitBytes("lli", "Number of bytes of global vars initialized"); + +// getPointerToGlobal - This returns the address of the specified global +// value.  This may involve code generation if it's a function. +// +void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { +  if (const Function *F = dyn_cast<Function>(GV)) +    return getPointerToFunction(F); + +  assert(GlobalAddress[GV] && "Global hasn't had an address allocated yet?"); +  return GlobalAddress[GV]; +} + + +GenericValue ExecutionEngine::getConstantValue(const Constant *C) { +  GenericValue Result; +#define GET_CONST_VAL(TY, CLASS) \ +  case Type::TY##TyID: Result.TY##Val = cast<CLASS>(C)->getValue(); break + +  switch (C->getType()->getPrimitiveID()) { +    GET_CONST_VAL(Bool   , ConstantBool); +    GET_CONST_VAL(UByte  , ConstantUInt); +    GET_CONST_VAL(SByte  , ConstantSInt); +    GET_CONST_VAL(UShort , ConstantUInt); +    GET_CONST_VAL(Short  , ConstantSInt); +    GET_CONST_VAL(UInt   , ConstantUInt); +    GET_CONST_VAL(Int    , ConstantSInt); +    GET_CONST_VAL(ULong  , ConstantUInt); +    GET_CONST_VAL(Long   , ConstantSInt); +    GET_CONST_VAL(Float  , ConstantFP); +    GET_CONST_VAL(Double , ConstantFP); +#undef GET_CONST_VAL +  case Type::PointerTyID: +    if (isa<ConstantPointerNull>(C)) { +      Result.PointerVal = 0; +    } else if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(C)){ +      Result = PTOGV(getPointerToGlobal(CPR->getValue())); + +    } else { +      assert(0 && "Unknown constant pointer type!"); +    } +    break; +  default: +    cout << "ERROR: Constant unimp for type: " << C->getType() << "\n"; +  } +  return Result; +} + +void ExecutionEngine::StoreValueToMemory(GenericValue Val, GenericValue *Ptr, +				     const Type *Ty) { +  if (getTargetData().isLittleEndian()) { +    switch (Ty->getPrimitiveID()) { +    case Type::BoolTyID: +    case Type::UByteTyID: +    case Type::SByteTyID:   Ptr->Untyped[0] = Val.UByteVal; break; +    case Type::UShortTyID: +    case Type::ShortTyID:   Ptr->Untyped[0] = Val.UShortVal & 255; +                            Ptr->Untyped[1] = (Val.UShortVal >> 8) & 255; +                            break; +    case Type::FloatTyID: +    case Type::UIntTyID: +    case Type::IntTyID:     Ptr->Untyped[0] =  Val.UIntVal        & 255; +                            Ptr->Untyped[1] = (Val.UIntVal >>  8) & 255; +                            Ptr->Untyped[2] = (Val.UIntVal >> 16) & 255; +                            Ptr->Untyped[3] = (Val.UIntVal >> 24) & 255; +                            break; +    case Type::DoubleTyID: +    case Type::ULongTyID: +    case Type::LongTyID:     +    case Type::PointerTyID: Ptr->Untyped[0] =  Val.ULongVal        & 255; +                            Ptr->Untyped[1] = (Val.ULongVal >>  8) & 255; +                            Ptr->Untyped[2] = (Val.ULongVal >> 16) & 255; +                            Ptr->Untyped[3] = (Val.ULongVal >> 24) & 255; +                            Ptr->Untyped[4] = (Val.ULongVal >> 32) & 255; +                            Ptr->Untyped[5] = (Val.ULongVal >> 40) & 255; +                            Ptr->Untyped[6] = (Val.ULongVal >> 48) & 255; +                            Ptr->Untyped[7] = (Val.ULongVal >> 56) & 255; +                            break; +    default: +      cout << "Cannot store value of type " << Ty << "!\n"; +    } +  } else { +    switch (Ty->getPrimitiveID()) { +    case Type::BoolTyID: +    case Type::UByteTyID: +    case Type::SByteTyID:   Ptr->Untyped[0] = Val.UByteVal; break; +    case Type::UShortTyID: +    case Type::ShortTyID:   Ptr->Untyped[1] = Val.UShortVal & 255; +                            Ptr->Untyped[0] = (Val.UShortVal >> 8) & 255; +                            break; +    case Type::FloatTyID: +    case Type::UIntTyID: +    case Type::IntTyID:     Ptr->Untyped[3] =  Val.UIntVal        & 255; +                            Ptr->Untyped[2] = (Val.UIntVal >>  8) & 255; +                            Ptr->Untyped[1] = (Val.UIntVal >> 16) & 255; +                            Ptr->Untyped[0] = (Val.UIntVal >> 24) & 255; +                            break; +    case Type::DoubleTyID: +    case Type::ULongTyID: +    case Type::LongTyID:     +    case Type::PointerTyID: Ptr->Untyped[7] =  Val.ULongVal        & 255; +                            Ptr->Untyped[6] = (Val.ULongVal >>  8) & 255; +                            Ptr->Untyped[5] = (Val.ULongVal >> 16) & 255; +                            Ptr->Untyped[4] = (Val.ULongVal >> 24) & 255; +                            Ptr->Untyped[3] = (Val.ULongVal >> 32) & 255; +                            Ptr->Untyped[2] = (Val.ULongVal >> 40) & 255; +                            Ptr->Untyped[1] = (Val.ULongVal >> 48) & 255; +                            Ptr->Untyped[0] = (Val.ULongVal >> 56) & 255; +                            break; +    default: +      cout << "Cannot store value of type " << Ty << "!\n"; +    } +  } +} + +// InitializeMemory - Recursive function to apply a Constant value into the +// specified memory location... +// +void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { +  if (Init->getType()->isFirstClassType()) { +    GenericValue Val = getConstantValue(Init); +    StoreValueToMemory(Val, (GenericValue*)Addr, Init->getType()); +    return; +  } + +  switch (Init->getType()->getPrimitiveID()) { +  case Type::ArrayTyID: { +    const ConstantArray *CPA = cast<ConstantArray>(Init); +    const vector<Use> &Val = CPA->getValues(); +    unsigned ElementSize =  +      getTargetData().getTypeSize(cast<ArrayType>(CPA->getType())->getElementType()); +    for (unsigned i = 0; i < Val.size(); ++i) +      InitializeMemory(cast<Constant>(Val[i].get()), (char*)Addr+i*ElementSize); +    return; +  } + +  case Type::StructTyID: { +    const ConstantStruct *CPS = cast<ConstantStruct>(Init); +    const StructLayout *SL = +      getTargetData().getStructLayout(cast<StructType>(CPS->getType())); +    const vector<Use> &Val = CPS->getValues(); +    for (unsigned i = 0; i < Val.size(); ++i) +      InitializeMemory(cast<Constant>(Val[i].get()), +                       (char*)Addr+SL->MemberOffsets[i]); +    return; +  } + +  default: +    std::cerr << "Bad Type: " << Init->getType() << "\n"; +    assert(0 && "Unknown constant type to initialize memory with!"); +  } +} + + + +void *ExecutionEngine::CreateArgv(const std::vector<std::string> &InputArgv) { +  // Pointers are 64 bits... +  PointerTy *Result = new PointerTy[InputArgv.size()+1];  // 64 bit assumption +  DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); + +  for (unsigned i = 0; i < InputArgv.size(); ++i) { +    unsigned Size = InputArgv[i].size()+1; +    char *Dest = new char[Size]; +    DEBUG(std::cerr << "ARGV[" << i << "] = " << (void*)Dest << "\n"); + +    copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); +    Dest[Size-1] = 0; + +    // Endian safe: Result[i] = (PointerTy)Dest; +    StoreValueToMemory(PTOGV(Dest), (GenericValue*)(Result+i), +                       Type::LongTy);  // 64 bit assumption +  } + +  Result[InputArgv.size()] = 0; +  return Result; +} + +/// EmitGlobals - Emit all of the global variables to memory, storing their +/// addresses into GlobalAddress.  This must make sure to copy the contents of +/// their initializers into the memory. +/// +void ExecutionEngine::emitGlobals() { +  const TargetData &TD = getTargetData(); +   +  // Loop over all of the global variables in the program, allocating the memory +  // to hold them. +  for (Module::giterator I = getModule().gbegin(), E = getModule().gend(); +       I != E; ++I) +    if (!I->isExternal()) { +      // Get the type of the global... +      const Type *Ty = I->getType()->getElementType(); +       +      // Allocate some memory for it! +      unsigned Size = TD.getTypeSize(Ty); +      GlobalAddress[I] = new char[Size]; +      NumInitBytes += Size; + +      DEBUG(std::cerr << "Global '" << I->getName() << "' -> " +	              << (void*)GlobalAddress[I] << "\n"); +    } else { +      assert(0 && "References to external globals not handled yet!"); +    } +   +  // Now that all of the globals are set up in memory, loop through them all and +  // initialize their contents. +  for (Module::giterator I = getModule().gbegin(), E = getModule().gend(); +       I != E; ++I) +    if (!I->isExternal()) +      InitializeMemory(I->getInitializer(), GlobalAddress[I]); +} + diff --git a/llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp b/llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp new file mode 100644 index 00000000000..678c77a74a8 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Interpreter/Interpreter.cpp @@ -0,0 +1,56 @@ +//===- Interpreter.cpp - Top-Level LLVM Interpreter Implementation --------===// +// +// This file implements the top-level functionality for the LLVM interpreter. +// This interpreter is designed to be a very simple, portable, inefficient +// interpreter. +// +//===----------------------------------------------------------------------===// + +#include "Interpreter.h" +#include "llvm/Target/TargetMachineImpls.h" + +/// createInterpreter - Create a new interpreter object.  This can never fail. +/// +ExecutionEngine *ExecutionEngine::createInterpreter(Module *M, +						    unsigned Config, +						    bool DebugMode, +						    bool TraceMode) { +  return new Interpreter(M, Config, DebugMode, TraceMode); +} + +//===----------------------------------------------------------------------===// +// Interpreter ctor - Initialize stuff +// +Interpreter::Interpreter(Module *M, unsigned Config, +			 bool DebugMode, bool TraceMode) +  : ExecutionEngine(M), ExitCode(0), Debug(DebugMode), Trace(TraceMode), +    CurFrame(-1), TD("lli", (Config & TM::EndianMask) == TM::LittleEndian, +		     1, 4, +		     (Config & TM::PtrSizeMask) == TM::PtrSize64 ? 8 : 4, +		     (Config & TM::PtrSizeMask) == TM::PtrSize64 ? 8 : 4) { + +  setTargetData(TD); +  // Initialize the "backend" +  initializeExecutionEngine(); +  initializeExternalMethods(); +  CW.setModule(M);  // Update Writer +} + +/// run - Start execution with the specified function and arguments. +/// +int Interpreter::run(const std::string &MainFunction, +		     const std::vector<std::string> &Args) { +  // Start interpreter into the main function... +  // +  if (!callMainMethod(MainFunction, Args) && !Debug) { +    // If not in debug mode and if the call succeeded, run the code now... +    run(); +  } + +  // If debug mode, allow the user to interact... also, if the user pressed  +  // ctrl-c or execution hit an error, enter the event loop... +  if (Debug || isStopped()) +    handleUserInput(); +  return ExitCode; +} + diff --git a/llvm/lib/ExecutionEngine/Interpreter/Makefile b/llvm/lib/ExecutionEngine/Interpreter/Makefile new file mode 100644 index 00000000000..1a7d3bfbab1 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Interpreter/Makefile @@ -0,0 +1,4 @@ +LEVEL = ../../.. +LIBRARYNAME = lli-interpreter + +include $(LEVEL)/Makefile.common diff --git a/llvm/lib/ExecutionEngine/JIT/Callback.cpp b/llvm/lib/ExecutionEngine/JIT/Callback.cpp new file mode 100644 index 00000000000..b843e106895 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JIT/Callback.cpp @@ -0,0 +1,62 @@ +//===-- Callback.cpp - Trap handler for function resolution ---------------===// +// +// This file defines the SIGSEGV handler which is invoked when a reference to a +// non-codegen'd function is found. +// +//===----------------------------------------------------------------------===// + +#include "VM.h" +#include "Support/Statistic.h" +#include <signal.h> +#include <ucontext.h> +#include <iostream> + +static VM *TheVM = 0; + +static void TrapHandler(int TN, siginfo_t *SI, ucontext_t *ucp) { +  assert(TN == SIGSEGV && "Should be SIGSEGV!"); + +#ifdef REG_EIP   /* this code does not compile on Sparc! */ +  if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 || +      ucp->uc_mcontext.gregs[REG_EIP] != 0) { +    std::cerr << "Bad SEGV encountered!\n"; +    abort(); +  } + +  // The call instruction should have pushed the return value onto the stack... +  unsigned RefAddr = *(unsigned*)ucp->uc_mcontext.gregs[REG_ESP]; +  RefAddr -= 4;  // Backtrack to the reference itself... + +  DEBUG(std::cerr << "In SEGV handler! Addr=0x" << std::hex << RefAddr +                  << " ESP=0x" << ucp->uc_mcontext.gregs[REG_ESP] << std::dec +                  << ": Resolving call to function: " +                  << TheVM->getFunctionReferencedName((void*)RefAddr) << "\n"); + +  // Sanity check to make sure this really is a call instruction... +  assert(((unsigned char*)RefAddr)[-1] == 0xE8 && "Not a call instr!"); +   +  unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RefAddr); + +  // Rewrite the call target... so that we don't fault every time we execute +  // the call. +  *(unsigned*)RefAddr = NewVal-RefAddr-4;     + +  // Change the instruction pointer to be the real target of the call... +  ucp->uc_mcontext.gregs[REG_EIP] = NewVal; + +#endif +} + + +void VM::registerCallback() { +  TheVM = this; + +  // Register the signal handler... +  struct sigaction SA; +  SA.sa_sigaction = (void (*)(int, siginfo_t*, void*))TrapHandler; +  sigfillset(&SA.sa_mask);               // Block all signals while codegen'ing +  SA.sa_flags = SA_NOCLDSTOP|SA_SIGINFO; // Get siginfo +  sigaction(SIGSEGV, &SA, 0);            // Install the handler +} + + diff --git a/llvm/lib/ExecutionEngine/JIT/Emitter.cpp b/llvm/lib/ExecutionEngine/JIT/Emitter.cpp new file mode 100644 index 00000000000..253a229a381 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JIT/Emitter.cpp @@ -0,0 +1,107 @@ +//===-- Emitter.cpp - Write machine code to executable memory -------------===// +// +// This file defines a MachineCodeEmitter object that is used by Jello to write +// machine code to memory and remember where relocatable values lie. +// +//===----------------------------------------------------------------------===// + +#include "VM.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Function.h" +#include "Support/Statistic.h" + +namespace { +  Statistic<> NumBytes("jello", "Number of bytes of machine code compiled"); + +  class Emitter : public MachineCodeEmitter { +    VM &TheVM; + +    unsigned char *CurBlock; +    unsigned char *CurByte; +     +    std::vector<std::pair<BasicBlock*, unsigned *> > BBRefs; +    std::map<BasicBlock*, unsigned> BBLocations; +  public: +    Emitter(VM &vm) : TheVM(vm) {} + +    virtual void startFunction(MachineFunction &F); +    virtual void finishFunction(MachineFunction &F); +    virtual void startBasicBlock(MachineBasicBlock &BB); +    virtual void emitByte(unsigned char B); +    virtual void emitPCRelativeDisp(Value *V); +    virtual void emitGlobalAddress(GlobalValue *V); +  }; +} + +MachineCodeEmitter *VM::createEmitter(VM &V) { +  return new Emitter(V); +} + + +#define _POSIX_MAPPED_FILES +#include <unistd.h> +#include <sys/mman.h> + +static void *getMemory() { +  return mmap(0, 4096*2, PROT_READ|PROT_WRITE|PROT_EXEC, +              MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); +} + + +void Emitter::startFunction(MachineFunction &F) { +  CurBlock = (unsigned char *)getMemory(); +  CurByte = CurBlock;  // Start writing at the beginning of the fn. +  TheVM.addGlobalMapping(F.getFunction(), CurBlock); +} + +void Emitter::finishFunction(MachineFunction &F) { +  for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { +    unsigned Location = BBLocations[BBRefs[i].first]; +    unsigned *Ref = BBRefs[i].second; +    *Ref = Location-(unsigned)Ref-4; +  } +  BBRefs.clear(); +  BBLocations.clear(); + +  NumBytes += CurByte-CurBlock; + +  DEBUG(std::cerr << "Finished CodeGen of [" << std::hex << (unsigned)CurBlock +                  << std::dec << "] Function: " << F.getFunction()->getName() +                  << ": " << CurByte-CurBlock << " bytes of text\n"); +} + +void Emitter::startBasicBlock(MachineBasicBlock &BB) { +  BBLocations[BB.getBasicBlock()] = (unsigned)CurByte; +} + + +void Emitter::emitByte(unsigned char B) { +  *CurByte++ = B;   // Write the byte to memory +} + + +// emitPCRelativeDisp - For functions, just output a displacement that will +// cause a reference to the zero page, which will cause a seg-fault, causing +// things to get resolved on demand.  Keep track of these markers. +// +// For basic block references, keep track of where the references are so they +// may be patched up when the basic block is defined. +// +void Emitter::emitPCRelativeDisp(Value *V) { +  if (Function *F = dyn_cast<Function>(V)) { +    TheVM.addFunctionRef(CurByte, F); +    unsigned ZeroAddr = -(unsigned)CurByte-4; // Calculate displacement to null +    *(unsigned*)CurByte = ZeroAddr;           // 4 byte offset +    CurByte += 4; +  } else { +    BasicBlock *BB = cast<BasicBlock>(V);     // Keep track of reference... +    BBRefs.push_back(std::make_pair(BB, (unsigned*)CurByte)); +    CurByte += 4; +  } +} + +void Emitter::emitGlobalAddress(GlobalValue *V) { +  *(void**)CurByte = TheVM.getPointerToGlobal(V); +  CurByte += 4; +} diff --git a/llvm/lib/ExecutionEngine/JIT/GlobalVars.cpp b/llvm/lib/ExecutionEngine/JIT/GlobalVars.cpp new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/llvm/lib/ExecutionEngine/JIT/GlobalVars.cpp diff --git a/llvm/lib/ExecutionEngine/JIT/JIT.cpp b/llvm/lib/ExecutionEngine/JIT/JIT.cpp new file mode 100644 index 00000000000..b2b56a63e50 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JIT/JIT.cpp @@ -0,0 +1,53 @@ +//===-- JIT.cpp - LLVM Just in Time Compiler ------------------------------===// +// +// This file implements the top-level support for creating a Just-In-Time +// compiler for the current architecture. +// +//===----------------------------------------------------------------------===// + +#include "VM.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetMachineImpls.h" +#include "llvm/Module.h" + + +/// createJIT - Create an return a new JIT compiler if there is one available +/// for the current target.  Otherwise it returns null. +/// +ExecutionEngine *ExecutionEngine::createJIT(Module *M, unsigned Config) { +  // FIXME: This should be controlled by which subdirectory gets linked in! +#if !defined(i386) && !defined(__i386__) && !defined(__x86__) +  return 0; +#endif +  // Allocate a target... in the future this will be controllable on the +  // command line. +  TargetMachine *Target = allocateX86TargetMachine(Config); +  assert(Target && "Could not allocate X86 target machine!"); + +  // Create the virtual machine object... +  return new VM(M, Target); +} + +VM::VM(Module *M, TargetMachine *tm) : ExecutionEngine(M), TM(*tm) { +  setTargetData(TM.getTargetData()); +  MCE = createEmitter(*this);  // Initialize MCE +  setupPassManager(); +  registerCallback(); +} + +int VM::run(const std::string &FnName, const std::vector<std::string> &Args) { +  Function *F = getModule().getNamedFunction(FnName); +  if (F == 0) { +    std::cerr << "Could not find function '" << FnName <<"' in module!\n"; +    return 1; +  } + +  int(*PF)(int, char**) = (int(*)(int, char**))getPointerToFunction(F); +  assert(PF != 0 && "Null pointer to function?"); + +  // Build an argv vector... +  char **Argv = (char**)CreateArgv(Args); + +  // Call the main function... +  return PF(Args.size(), Argv); +} diff --git a/llvm/lib/ExecutionEngine/JIT/Makefile b/llvm/lib/ExecutionEngine/JIT/Makefile new file mode 100644 index 00000000000..bc3f709a995 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JIT/Makefile @@ -0,0 +1,4 @@ +LEVEL = ../../.. +LIBRARYNAME = lli-jit + +include $(LEVEL)/Makefile.common diff --git a/llvm/lib/ExecutionEngine/JIT/VM.cpp b/llvm/lib/ExecutionEngine/JIT/VM.cpp new file mode 100644 index 00000000000..f66d4d7b7ea --- /dev/null +++ b/llvm/lib/ExecutionEngine/JIT/VM.cpp @@ -0,0 +1,84 @@ +//===-- jello.cpp - LLVM Just in Time Compiler ----------------------------===// +// +// 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/Target/TargetMachine.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/Function.h" +#include <dlfcn.h>    // dlsym access + + +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 +  if (TM.addPassesToJITCompile(PM)) { +    std::cerr << "lli: target '" << TM.getName() +              << "' doesn't support JIT compilation!\n"; +    abort(); +  } + +  // 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(); +  } +} + +void *VM::resolveFunctionReference(void *RefAddr) { +  Function *F = FunctionRefs[RefAddr]; +  assert(F && "Reference address not known!"); + +  void *Addr = getPointerToFunction(F); +  assert(Addr && "Pointer to function unknown!"); + +  FunctionRefs.erase(RefAddr); +  return Addr; +} + +const std::string &VM::getFunctionReferencedName(void *RefAddr) { +  return FunctionRefs[RefAddr]->getName(); +} + +static void NoopFn() {} + +/// getPointerToFunction - This method is used to get the address of the +/// specified function, compiling it if neccesary. +/// +void *VM::getPointerToFunction(const Function *F) { +  void *&Addr = GlobalAddress[F];   // Function already code gen'd +  if (Addr) return Addr; + +  if (F->isExternal()) { +    // If it's an external function, look it up in the process image... +    void *Ptr = dlsym(0, F->getName().c_str()); +    if (Ptr == 0) { +      std::cerr << "WARNING: Cannot resolve fn '" << F->getName() +                << "' using a dummy noop function instead!\n"; +      Ptr = (void*)NoopFn; +    } + +    return Addr = Ptr; +  } + +  // JIT all of the functions in the module.  Eventually this will JIT functions +  // on demand.  This has the effect of populating all of the non-external +  // functions into the GlobalAddress table. +  PM.run(getModule()); + +  assert(Addr && "Code generation didn't add function to GlobalAddress table!"); +  return Addr; +}  | 

