X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FExecutionEngine.cpp;h=7fb4ad3ae81bf063cf82bb1a7c8d19d7235ef6e7;hb=0050ef831912eea2377c815bc59c09ed828f2684;hp=b4baf9f8ffffbb91bfce5a7f006e354984ea6fde;hpb=70975eef572b9e132bbaade16ba9edb76f15f287;p=oota-llvm.git diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index b4baf9f8fff..7fb4ad3ae81 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -1,4 +1,11 @@ -//===-- ExecutionEngine.cpp - Common Implementation shared by EE's --------===// +//===-- ExecutionEngine.cpp - Common Implementation shared by EEs ---------===// +// +// 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 common interface used by the various execution engine // subclasses. @@ -6,51 +13,164 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "jit" -#include "ExecutionEngine.h" -#include "GenericValue.h" -#include "llvm/DerivedTypes.h" +#include "Interpreter/Interpreter.h" +#include "JIT/JIT.h" #include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" #include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/CodeGen/IntrinsicLowering.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/Target/TargetData.h" -#include "Support/Debug.h" -#include "Support/Statistic.h" -#include "Config/dlfcn.h" -#include "JIT/VM.h" -#include "Interpreter/Interpreter.h" +#include "llvm/Support/Debug.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/DynamicLinker.h" +using namespace llvm; -Statistic<> NumInitBytes("lli", "Number of bytes of global vars initialized"); +namespace { + Statistic<> NumInitBytes("lli", "Number of bytes of global vars initialized"); + Statistic<> NumGlobals ("lli", "Number of global vars initialized"); +} + +ExecutionEngine::ExecutionEngine(ModuleProvider *P) : + CurMod(*P->getModule()), MP(P) { + assert(P && "ModuleProvider is null?"); +} + +ExecutionEngine::ExecutionEngine(Module *M) : CurMod(*M), MP(0) { + assert(M && "Module is null?"); +} ExecutionEngine::~ExecutionEngine() { - delete &CurMod; + delete MP; } -ExecutionEngine *ExecutionEngine::create (Module *M, bool ForceInterpreter, - bool TraceMode) { +/// getGlobalValueAtAddress - Return the LLVM global value object that starts +/// at the specified address. +/// +const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) { + // If we haven't computed the reverse mapping yet, do so first. + if (GlobalAddressReverseMap.empty()) { + for (std::map::iterator I = + GlobalAddressMap.begin(), E = GlobalAddressMap.end(); I != E; ++I) + GlobalAddressReverseMap.insert(std::make_pair(I->second, I->first)); + } + + std::map::iterator I = + GlobalAddressReverseMap.find(Addr); + return I != GlobalAddressReverseMap.end() ? I->second : 0; +} + +// CreateArgv - Turn a vector of strings into a nice argv style array of +// pointers to null terminated strings. +// +static void *CreateArgv(ExecutionEngine *EE, + const std::vector &InputArgv) { + unsigned PtrSize = EE->getTargetData().getPointerSize(); + char *Result = new char[(InputArgv.size()+1)*PtrSize]; + + DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); + const Type *SBytePtr = PointerType::get(Type::SByteTy); + + 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"); + + std::copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); + Dest[Size-1] = 0; + + // Endian safe: Result[i] = (PointerTy)Dest; + EE->StoreValueToMemory(PTOGV(Dest), (GenericValue*)(Result+i*PtrSize), + SBytePtr); + } + + // Null terminate it + EE->StoreValueToMemory(PTOGV(0), + (GenericValue*)(Result+InputArgv.size()*PtrSize), + SBytePtr); + return Result; +} + +/// runFunctionAsMain - This is a helper function which wraps runFunction to +/// handle the common task of starting up main with the specified argc, argv, +/// and envp parameters. +int ExecutionEngine::runFunctionAsMain(Function *Fn, + const std::vector &argv, + const char * const * envp) { + std::vector GVArgs; + GenericValue GVArgc; + GVArgc.IntVal = argv.size(); + unsigned NumArgs = Fn->getFunctionType()->getNumParams(); + if (NumArgs) { + GVArgs.push_back(GVArgc); // Arg #0 = argc. + if (NumArgs > 1) { + GVArgs.push_back(PTOGV(CreateArgv(this, argv))); // Arg #1 = argv. + assert(((char **)GVTOP(GVArgs[1]))[0] && + "argv[0] was null after CreateArgv"); + if (NumArgs > 2) { + std::vector EnvVars; + for (unsigned i = 0; envp[i]; ++i) + EnvVars.push_back(envp[i]); + GVArgs.push_back(PTOGV(CreateArgv(this, EnvVars))); // Arg #2 = envp. + } + } + } + return runFunction(Fn, GVArgs).IntVal; +} + + + +/// If possible, create a JIT, unless the caller specifically requests an +/// Interpreter or there's an error. If even an Interpreter cannot be created, +/// NULL is returned. +/// +ExecutionEngine *ExecutionEngine::create(ModuleProvider *MP, + bool ForceInterpreter, + IntrinsicLowering *IL) { ExecutionEngine *EE = 0; - // If there is nothing that is forcing us to use the interpreter, make a JIT. - if (!ForceInterpreter && !TraceMode) - EE = VM::create(M); + // Unless the interpreter was explicitly selected, try making a JIT. + if (!ForceInterpreter) + EE = JIT::create(MP, IL); // If we can't make a JIT, make an interpreter instead. - if (EE == 0) - EE = Interpreter::create(M, TraceMode); + if (EE == 0) { + try { + Module *M = MP->materializeModule(); + try { + EE = Interpreter::create(M, IL); + } catch (...) { + std::cerr << "Error creating the interpreter!\n"; + } + } catch (std::string& errmsg) { + std::cerr << "Error reading the bytecode file: " << errmsg << "\n"; + } catch (...) { + std::cerr << "Error reading the bytecode file!\n"; + } + } + + if (EE == 0) delete IL; return EE; } -// getPointerToGlobal - This returns the address of the specified global -// value. This may involve code generation if it's a function. -// +/// 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 (Function *F = const_cast(dyn_cast(GV))) return getPointerToFunction(F); - assert(GlobalAddress[GV] && "Global hasn't had an address allocated yet?"); - return GlobalAddress[GV]; + assert(GlobalAddressMap[GV] && "Global hasn't had an address allocated yet?"); + return GlobalAddressMap[GV]; } +/// FIXME: document +/// GenericValue ExecutionEngine::getConstantValue(const Constant *C) { GenericValue Result; + if (isa(C)) return Result; if (ConstantExpr *CE = const_cast(dyn_cast(C))) { switch (CE->getOpcode()) { @@ -68,31 +188,66 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { // automatically fold, just the ones involving pointers won't. // Constant *Op = CE->getOperand(0); + GenericValue GV = getConstantValue(Op); // Handle cast of pointer to pointer... - if (Op->getType()->getPrimitiveID() == C->getType()->getPrimitiveID()) - return getConstantValue(Op); + if (Op->getType()->getTypeID() == C->getType()->getTypeID()) + return GV; // Handle a cast of pointer to any integral type... if (isa(Op->getType()) && C->getType()->isIntegral()) - return getConstantValue(Op); + return GV; - // Handle cast of long to pointer... - if (isa(C->getType()) && (Op->getType() == Type::LongTy || - Op->getType() == Type::ULongTy)) - return getConstantValue(Op); + // Handle cast of integer to a pointer... + if (isa(C->getType()) && Op->getType()->isIntegral()) + switch (Op->getType()->getTypeID()) { + case Type::BoolTyID: return PTOGV((void*)(uintptr_t)GV.BoolVal); + case Type::SByteTyID: return PTOGV((void*)( intptr_t)GV.SByteVal); + case Type::UByteTyID: return PTOGV((void*)(uintptr_t)GV.UByteVal); + case Type::ShortTyID: return PTOGV((void*)( intptr_t)GV.ShortVal); + case Type::UShortTyID: return PTOGV((void*)(uintptr_t)GV.UShortVal); + case Type::IntTyID: return PTOGV((void*)( intptr_t)GV.IntVal); + case Type::UIntTyID: return PTOGV((void*)(uintptr_t)GV.UIntVal); + case Type::LongTyID: return PTOGV((void*)( intptr_t)GV.LongVal); + case Type::ULongTyID: return PTOGV((void*)(uintptr_t)GV.ULongVal); + default: assert(0 && "Unknown integral type!"); + } break; } case Instruction::Add: - if (CE->getOperand(0)->getType() == Type::LongTy || - CE->getOperand(0)->getType() == Type::ULongTy) + switch (CE->getOperand(0)->getType()->getTypeID()) { + default: assert(0 && "Bad add type!"); abort(); + case Type::LongTyID: + case Type::ULongTyID: Result.LongVal = getConstantValue(CE->getOperand(0)).LongVal + getConstantValue(CE->getOperand(1)).LongVal; - else break; + case Type::IntTyID: + case Type::UIntTyID: + Result.IntVal = getConstantValue(CE->getOperand(0)).IntVal + + getConstantValue(CE->getOperand(1)).IntVal; + break; + case Type::ShortTyID: + case Type::UShortTyID: + Result.ShortVal = getConstantValue(CE->getOperand(0)).ShortVal + + getConstantValue(CE->getOperand(1)).ShortVal; + break; + case Type::SByteTyID: + case Type::UByteTyID: + Result.SByteVal = getConstantValue(CE->getOperand(0)).SByteVal + + getConstantValue(CE->getOperand(1)).SByteVal; + break; + case Type::FloatTyID: + Result.FloatVal = getConstantValue(CE->getOperand(0)).FloatVal + + getConstantValue(CE->getOperand(1)).FloatVal; + break; + case Type::DoubleTyID: + Result.DoubleVal = getConstantValue(CE->getOperand(0)).DoubleVal + + getConstantValue(CE->getOperand(1)).DoubleVal; + break; + } return Result; - default: break; } @@ -100,7 +255,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { abort(); } - switch (C->getType()->getPrimitiveID()) { + switch (C->getType()->getTypeID()) { #define GET_CONST_VAL(TY, CLASS) \ case Type::TY##TyID: Result.TY##Val = cast(C)->getValue(); break GET_CONST_VAL(Bool , ConstantBool); @@ -116,26 +271,28 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { GET_CONST_VAL(Double , ConstantFP); #undef GET_CONST_VAL case Type::PointerTyID: - if (isa(C)) { + if (isa(C)) Result.PointerVal = 0; - } else if (const ConstantPointerRef *CPR = dyn_cast(C)){ - Result = PTOGV(getPointerToGlobal(CPR->getValue())); - - } else { + else if (const Function *F = dyn_cast(C)) + Result = PTOGV(getPointerToFunctionOrStub(const_cast(F))); + else if (const GlobalVariable* GV = dyn_cast(C)) + Result = PTOGV(getOrEmitGlobalVariable(const_cast(GV))); + else assert(0 && "Unknown constant pointer type!"); - } break; default: - std::cout << "ERROR: Constant unimp for type: " << C->getType() << "\n"; + std::cout << "ERROR: Constant unimp for type: " << *C->getType() << "\n"; abort(); } return Result; } +/// FIXME: document +/// void ExecutionEngine::StoreValueToMemory(GenericValue Val, GenericValue *Ptr, - const Type *Ty) { + const Type *Ty) { if (getTargetData().isLittleEndian()) { - switch (Ty->getPrimitiveID()) { + switch (Ty->getTypeID()) { case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: Ptr->Untyped[0] = Val.UByteVal; break; @@ -165,10 +322,10 @@ void ExecutionEngine::StoreValueToMemory(GenericValue Val, GenericValue *Ptr, Ptr->Untyped[7] = (Val.ULongVal >> 56) & 255; break; default: - std::cout << "Cannot store value of type " << Ty << "!\n"; + std::cout << "Cannot store value of type " << *Ty << "!\n"; } } else { - switch (Ty->getPrimitiveID()) { + switch (Ty->getTypeID()) { case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: Ptr->Untyped[0] = Val.UByteVal; break; @@ -198,16 +355,18 @@ void ExecutionEngine::StoreValueToMemory(GenericValue Val, GenericValue *Ptr, Ptr->Untyped[0] = (Val.ULongVal >> 56) & 255; break; default: - std::cout << "Cannot store value of type " << Ty << "!\n"; + std::cout << "Cannot store value of type " << *Ty << "!\n"; } } } +/// FIXME: document +/// GenericValue ExecutionEngine::LoadValueFromMemory(GenericValue *Ptr, const Type *Ty) { GenericValue Result; if (getTargetData().isLittleEndian()) { - switch (Ty->getPrimitiveID()) { + switch (Ty->getTypeID()) { case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: Result.UByteVal = Ptr->Untyped[0]; break; @@ -241,7 +400,7 @@ GenericValue ExecutionEngine::LoadValueFromMemory(GenericValue *Ptr, abort(); } } else { - switch (Ty->getPrimitiveID()) { + switch (Ty->getTypeID()) { case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: Result.UByteVal = Ptr->Untyped[0]; break; @@ -282,20 +441,25 @@ GenericValue ExecutionEngine::LoadValueFromMemory(GenericValue *Ptr, // specified memory location... // void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { - if (Init->getType()->isFirstClassType()) { + if (isa(Init)) { + return; + } else if (Init->getType()->isFirstClassType()) { GenericValue Val = getConstantValue(Init); StoreValueToMemory(Val, (GenericValue*)Addr, Init->getType()); return; + } else if (isa(Init)) { + unsigned Size = getTargetData().getTypeSize(Init->getType()); + memset(Addr, 0, Size); + return; } - switch (Init->getType()->getPrimitiveID()) { + switch (Init->getType()->getTypeID()) { case Type::ArrayTyID: { const ConstantArray *CPA = cast(Init); - const std::vector &Val = CPA->getValues(); unsigned ElementSize = getTargetData().getTypeSize(cast(CPA->getType())->getElementType()); - for (unsigned i = 0; i < Val.size(); ++i) - InitializeMemory(cast(Val[i].get()), (char*)Addr+i*ElementSize); + for (unsigned i = 0, e = CPA->getNumOperands(); i != e; ++i) + InitializeMemory(CPA->getOperand(i), (char*)Addr+i*ElementSize); return; } @@ -303,15 +467,13 @@ void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { const ConstantStruct *CPS = cast(Init); const StructLayout *SL = getTargetData().getStructLayout(cast(CPS->getType())); - const std::vector &Val = CPS->getValues(); - for (unsigned i = 0; i < Val.size(); ++i) - InitializeMemory(cast(Val[i].get()), - (char*)Addr+SL->MemberOffsets[i]); + for (unsigned i = 0, e = CPS->getNumOperands(); i != e; ++i) + InitializeMemory(CPS->getOperand(i), (char*)Addr+SL->MemberOffsets[i]); return; } default: - std::cerr << "Bad Type: " << Init->getType() << "\n"; + std::cerr << "Bad Type: " << *Init->getType() << "\n"; assert(0 && "Unknown constant type to initialize memory with!"); } } @@ -333,21 +495,12 @@ void ExecutionEngine::emitGlobals() { // 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"); + addGlobalMapping(I, new char[Size]); } else { - // On Sparc, RTLD_SELF is already defined and it's not zero - // Linux/x86 wants to use a 0, other systems may differ -#ifndef RTLD_SELF -#define RTLD_SELF 0 -#endif - // External variable reference, try to use dlsym to get a pointer to it in - // the LLI image. - if (void *SymAddr = dlsym(RTLD_SELF, I->getName().c_str())) - GlobalAddress[I] = SymAddr; + // External variable reference. Try to use the dynamic loader to + // get a pointer to it. + if (void *SymAddr = GetAddressOfSymbol(I->getName().c_str())) + addGlobalMapping(I, SymAddr); else { std::cerr << "Could not resolve external global address: " << I->getName() << "\n"; @@ -360,6 +513,24 @@ void ExecutionEngine::emitGlobals() { for (Module::giterator I = getModule().gbegin(), E = getModule().gend(); I != E; ++I) if (!I->isExternal()) - InitializeMemory(I->getInitializer(), GlobalAddress[I]); + EmitGlobalVariable(I); } +// EmitGlobalVariable - This method emits the specified global variable to the +// address specified in GlobalAddresses, or allocates new memory if it's not +// already in the map. +void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) { + void *GA = getPointerToGlobalIfAvailable(GV); + DEBUG(std::cerr << "Global '" << GV->getName() << "' -> " << GA << "\n"); + + const Type *ElTy = GV->getType()->getElementType(); + if (GA == 0) { + // If it's not already specified, allocate memory for the global. + GA = new char[getTargetData().getTypeSize(ElTy)]; + addGlobalMapping(GV, GA); + } + + InitializeMemory(GV->getInitializer(), GA); + NumInitBytes += getTargetData().getTypeSize(ElTy); + ++NumGlobals; +}