From fe11a97fcde7c63109c3ad36570657807d0cd6ef Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 23 Dec 2002 23:59:41 +0000 Subject: Substantial changes to refactor LLI to incorporate both the Jello JIT and the traditional LLI interpreter git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5125 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ExecutionEngine/Interpreter/Execution.cpp | 246 ++------------------- .../Interpreter/ExecutionAnnotations.h | 28 --- .../Interpreter/ExternalFunctions.cpp | 9 +- lib/ExecutionEngine/Interpreter/Interpreter.h | 56 ++--- lib/ExecutionEngine/Interpreter/Support.cpp | 3 +- lib/ExecutionEngine/Interpreter/UserInput.cpp | 74 +------ lib/ExecutionEngine/Makefile | 6 +- tools/lli/Makefile | 6 +- tools/lli/lli.cpp | 134 ++++++----- 9 files changed, 147 insertions(+), 415 deletions(-) diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index b400a8a82f..65c7563597 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -6,6 +6,8 @@ #include "Interpreter.h" #include "ExecutionAnnotations.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Function.h" #include "llvm/iPHINode.h" #include "llvm/iOther.h" #include "llvm/iTerminators.h" @@ -13,7 +15,6 @@ #include "llvm/DerivedTypes.h" #include "llvm/Constants.h" #include "llvm/Assembly/Writer.h" -#include "llvm/Target/TargetData.h" #include "Support/CommandLine.h" #include "Support/Statistic.h" #include // For fmod @@ -23,11 +24,14 @@ using std::vector; using std::cout; using std::cerr; +Interpreter *TheEE = 0; + namespace { Statistic<> NumDynamicInsts("lli", "Number of dynamic instructions executed"); cl::opt - QuietMode("quiet", cl::desc("Do not emit any non-program output")); + QuietMode("quiet", cl::desc("Do not emit any non-program output"), + cl::init(true)); cl::alias QuietModeA("q", cl::desc("Alias for -quiet"), cl::aliasopt(QuietMode)); @@ -43,10 +47,8 @@ namespace { // Create a TargetData structure to handle memory addressing and size/alignment // computations // -TargetData TD("lli Interpreter"); CachedWriter CW; // Object to accelerate printing of LLVM - #ifdef PROFILE_STRUCTURE_FIELDS static cl::opt ProfileStructureFields("profilestructfields", @@ -87,48 +89,12 @@ static unsigned getOperandSlot(Value *V) { return SN->SlotNum; } -#define GET_CONST_VAL(TY, CLASS) \ - case Type::TY##TyID: Result.TY##Val = cast(C)->getValue(); break - // Operations used by constant expr implementations... static GenericValue executeCastOperation(Value *Src, const Type *DestTy, ExecutionContext &SF); -static GenericValue executeGEPOperation(Value *Src, User::op_iterator IdxBegin, - User::op_iterator IdxEnd, - ExecutionContext &SF); static GenericValue executeAddInst(GenericValue Src1, GenericValue Src2, const Type *Ty, ExecutionContext &SF); -static GenericValue getConstantValue(const Constant *C) { - GenericValue Result; - 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); - case Type::PointerTyID: - if (isa(C)) { - Result.PointerVal = 0; - } else if (const ConstantPointerRef *CPR = dyn_cast(C)){ - GlobalAddress *Address = - (GlobalAddress*)CPR->getValue()->getOrCreateAnnotation(GlobalAddressAID); - Result.PointerVal = (PointerTy)Address->Ptr; - } else { - assert(0 && "Unknown constant pointer type!"); - } - break; - default: - cout << "ERROR: Constant unimp for type: " << C->getType() << "\n"; - } - return Result; -} static GenericValue getOperandValue(Value *V, ExecutionContext &SF) { if (ConstantExpr *CE = dyn_cast(V)) { @@ -136,8 +102,8 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) { case Instruction::Cast: return executeCastOperation(CE->getOperand(0), CE->getType(), SF); case Instruction::GetElementPtr: - return executeGEPOperation(CE->getOperand(0), CE->op_begin()+1, - CE->op_end(), SF); + return TheEE->executeGEPOperation(CE->getOperand(0), CE->op_begin()+1, + CE->op_end(), SF); case Instruction::Add: return executeAddInst(getOperandValue(CE->getOperand(0), SF), getOperandValue(CE->getOperand(1), SF), @@ -148,13 +114,9 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) { { GenericValue V; return V; } } } else if (Constant *CPV = dyn_cast(V)) { - return getConstantValue(CPV); + return TheEE->getConstantValue(CPV); } else if (GlobalValue *GV = dyn_cast(V)) { - GlobalAddress *Address = - (GlobalAddress*)GV->getOrCreateAnnotation(GlobalAddressAID); - GenericValue Result; - Result.PointerVal = (PointerTy)(GenericValue*)Address->Ptr; - return Result; + return PTOGV(TheEE->getPointerToGlobal(GV)); } else { unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value unsigned OpSlot = getOperandSlot(V); @@ -201,85 +163,12 @@ static void SetValue(Value *V, GenericValue Val, ExecutionContext &SF) { //===----------------------------------------------------------------------===// void Interpreter::initializeExecutionEngine() { + TheEE = this; AnnotationManager::registerAnnotationFactory(MethodInfoAID, &MethodInfo::Create); - AnnotationManager::registerAnnotationFactory(GlobalAddressAID, - &GlobalAddress::Create); initializeSignalHandlers(); } -static void StoreValueToMemory(GenericValue Val, GenericValue *Ptr, - const Type *Ty); - -// InitializeMemory - Recursive function to apply a Constant value into the -// specified memory location... -// -static void InitializeMemory(const Constant *Init, char *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(Init); - const vector &Val = CPA->getValues(); - unsigned ElementSize = - TD.getTypeSize(cast(CPA->getType())->getElementType()); - for (unsigned i = 0; i < Val.size(); ++i) - InitializeMemory(cast(Val[i].get()), Addr+i*ElementSize); - return; - } - - case Type::StructTyID: { - const ConstantStruct *CPS = cast(Init); - const StructLayout *SL=TD.getStructLayout(cast(CPS->getType())); - const vector &Val = CPS->getValues(); - for (unsigned i = 0; i < Val.size(); ++i) - InitializeMemory(cast(Val[i].get()), - Addr+SL->MemberOffsets[i]); - return; - } - - default: - CW << "Bad Type: " << Init->getType() << "\n"; - assert(0 && "Unknown constant type to initialize memory with!"); - } -} - -Annotation *GlobalAddress::Create(AnnotationID AID, const Annotable *O, void *){ - assert(AID == GlobalAddressAID); - - // This annotation will only be created on GlobalValue objects... - GlobalValue *GVal = cast((Value*)O); - - if (isa(GVal)) { - // The GlobalAddress object for a function is just a pointer to function - // itself. Don't delete it when the annotation is gone though! - return new GlobalAddress(GVal, false); - } - - // Handle the case of a global variable... - assert(isa(GVal) && - "Global value found that isn't a function or global variable!"); - GlobalVariable *GV = cast(GVal); - - // First off, we must allocate space for the global variable to point at... - const Type *Ty = GV->getType()->getElementType(); // Type to be allocated - - // Allocate enough memory to hold the type... - void *Addr = calloc(1, TD.getTypeSize(Ty)); - assert(Addr != 0 && "Null pointer returned by malloc!"); - - // Initialize the memory if there is an initializer... - if (GV->hasInitializer()) - InitializeMemory(GV->getInitializer(), (char*)Addr); - - return new GlobalAddress(Addr, true); // Simply invoke the ctor -} - //===----------------------------------------------------------------------===// // Binary Instruction Implementations //===----------------------------------------------------------------------===// @@ -760,8 +649,7 @@ void Interpreter::executeAllocInst(AllocationInst &I, ExecutionContext &SF) { // FIXME: Don't use CALLOC, use a tainted malloc. void *Memory = calloc(NumElements, TD.getTypeSize(Ty)); - GenericValue Result; - Result.PointerVal = (PointerTy)Memory; + GenericValue Result = PTOGV(Memory); assert(Result.PointerVal != 0 && "Null pointer returned by malloc!"); SetValue(&I, Result, SF); @@ -773,15 +661,15 @@ static void executeFreeInst(FreeInst &I, ExecutionContext &SF) { assert(isa(I.getOperand(0)->getType()) && "Freeing nonptr?"); GenericValue Value = getOperandValue(I.getOperand(0), SF); // TODO: Check to make sure memory is allocated - free((void*)Value.PointerVal); // Free memory + free(GVTOP(Value)); // Free memory } // getElementOffset - The workhorse for getelementptr. // -static GenericValue executeGEPOperation(Value *Ptr, User::op_iterator I, - User::op_iterator E, - ExecutionContext &SF) { +GenericValue Interpreter::executeGEPOperation(Value *Ptr, User::op_iterator I, + User::op_iterator E, + ExecutionContext &SF) { assert(isa(Ptr->getType()) && "Cannot getElementOffset of a nonpointer type!"); @@ -834,13 +722,13 @@ static GenericValue executeGEPOperation(Value *Ptr, User::op_iterator I, } static void executeGEPInst(GetElementPtrInst &I, ExecutionContext &SF) { - SetValue(&I, executeGEPOperation(I.getPointerOperand(), + SetValue(&I, TheEE->executeGEPOperation(I.getPointerOperand(), I.idx_begin(), I.idx_end(), SF), SF); } -static void executeLoadInst(LoadInst &I, ExecutionContext &SF) { +void Interpreter::executeLoadInst(LoadInst &I, ExecutionContext &SF) { GenericValue SRC = getOperandValue(I.getPointerOperand(), SF); - GenericValue *Ptr = (GenericValue*)SRC.PointerVal; + GenericValue *Ptr = (GenericValue*)GVTOP(SRC); GenericValue Result; if (TD.isLittleEndian()) { @@ -910,102 +798,14 @@ static void executeLoadInst(LoadInst &I, ExecutionContext &SF) { SetValue(&I, Result, SF); } -static void StoreValueToMemory(GenericValue Val, GenericValue *Ptr, - const Type *Ty) { - if (TD.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"; - } - } -} - -static void executeStoreInst(StoreInst &I, ExecutionContext &SF) { +void Interpreter::executeStoreInst(StoreInst &I, ExecutionContext &SF) { GenericValue Val = getOperandValue(I.getOperand(0), SF); GenericValue SRC = getOperandValue(I.getPointerOperand(), SF); - StoreValueToMemory(Val, (GenericValue *)SRC.PointerVal, + StoreValueToMemory(Val, (GenericValue *)GVTOP(SRC), I.getOperand(0)->getType()); } -GenericValue Interpreter::CreateArgv(const std::vector &InputArgv){ - // Pointers are 64 bits... - PointerTy *Result = new PointerTy[InputArgv.size()+1]; // 64 bit assumption - - for (unsigned i = 0; i < InputArgv.size(); ++i) { - unsigned Size = InputArgv[i].size()+1; - char *Dest = new char[Size]; - copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); - Dest[Size-1] = 0; - - GenericValue GV; GV.PointerVal = (PointerTy)Dest; - // Endian safe: Result[i] = (PointerTy)Dest; - StoreValueToMemory(GV, (GenericValue*)(Result+i), - Type::LongTy); // 64 bit assumption - } - - Result[InputArgv.size()] = 0; - GenericValue GV; GV.PointerVal = (PointerTy)Result; - return GV; -} - //===----------------------------------------------------------------------===// // Miscellaneous Instruction Implementations @@ -1022,7 +822,7 @@ void Interpreter::executeCallInst(CallInst &I, ExecutionContext &SF) { // and treat it as a function pointer. GenericValue SRC = getOperandValue(I.getCalledValue(), SF); - callMethod((Function*)SRC.PointerVal, ArgVals); + callMethod((Function*)GVTOP(SRC), ArgVals); } static void executePHINode(PHINode &I, ExecutionContext &SF) { @@ -1433,7 +1233,7 @@ void Interpreter::printValue(const Type *Ty, GenericValue V) { case Type::ULongTyID: cout << (unsigned long)V.ULongVal; break; case Type::FloatTyID: cout << V.FloatVal; break; case Type::DoubleTyID: cout << V.DoubleVal; break; - case Type::PointerTyID:cout << (void*)V.PointerVal; break; + case Type::PointerTyID:cout << (void*)GVTOP(V); break; default: cout << "- Don't know how to print value of this type!"; break; diff --git a/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h b/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h index 913e861595..1a5c7fee98 100644 --- a/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h +++ b/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h @@ -90,32 +90,4 @@ static AnnotationID BreakpointAID( // Just use an Annotation directly, Breakpoint is currently just a marker -//===----------------------------------------------------------------------===// -// Support for the GlobalAddress annotation -//===----------------------------------------------------------------------===// - -// This annotation (attached only to GlobalValue objects) is used to hold the -// address of the chunk of memory that represents a global value. For -// Functions, this pointer is the Function object pointer that represents it. -// For global variables, this is the dynamically allocated (and potentially -// initialized) chunk of memory for the global. This annotation is created on -// demand. -// -static AnnotationID GlobalAddressAID( - AnnotationManager::getID("Interpreter::GlobalAddress")); - -struct GlobalAddress : public Annotation { - void *Ptr; // The pointer itself - bool Delete; // Should I delete them memory on destruction? - - GlobalAddress(void *ptr, bool d) : Annotation(GlobalAddressAID), Ptr(ptr), - Delete(d) {} - ~GlobalAddress() { if (Delete) free(Ptr); } - - // Create - Factory function to allow GlobalAddress annotations to be - // created on demand. - // - static Annotation *Create(AnnotationID AID, const Annotable *O, void *); -}; - #endif diff --git a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp index 79e730f0ec..0d8cae2fea 100644 --- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp +++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp @@ -12,6 +12,7 @@ #include "Interpreter.h" #include "ExecutionAnnotations.h" +#include "llvm/Module.h" #include "llvm/DerivedTypes.h" #include "llvm/SymbolTable.h" #include "llvm/Target/TargetData.h" @@ -23,8 +24,6 @@ using std::vector; using std::cout; -extern TargetData TD; - typedef GenericValue (*ExFunc)(FunctionType *, const vector &); static std::map Functions; static std::map FuncNames; @@ -440,8 +439,8 @@ static FILE *getFILE(PointerTy Ptr) { static PointerTy IOBBase = 0; static unsigned FILESize; - if (LastMod != TheInterpreter->getModule()) { // Module change or initialize? - Module *M = LastMod = TheInterpreter->getModule(); + if (LastMod != &TheInterpreter->getModule()) { // Module change or initialize? + Module *M = LastMod = &TheInterpreter->getModule(); // Check to see if the currently loaded module contains an __iob symbol... GlobalVariable *IOB = 0; @@ -456,6 +455,7 @@ static FILE *getFILE(PointerTy Ptr) { if (IOB) break; } +#if 0 /// FIXME! __iob support for LLI // If we found an __iob symbol now, find out what the actual address it's // held in is... if (IOB) { @@ -472,6 +472,7 @@ static FILE *getFILE(PointerTy Ptr) { else FILESize = 16*8; // Default size } +#endif } // Check to see if this is a reference to __iob... diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index c0d8b75aca..586828a1d1 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -10,36 +10,23 @@ // Uncomment this line to enable profiling of structure field accesses. //#define PROFILE_STRUCTURE_FIELDS 1 -#include "llvm/Module.h" +#include "../ExecutionEngine.h" #include "Support/DataTypes.h" #include "llvm/Assembly/CachedWriter.h" +#include "llvm/Target/TargetData.h" +#include "llvm/BasicBlock.h" +#include "../GenericValue.h" -extern CachedWriter CW; // Object to accellerate printing of LLVM +extern CachedWriter CW; // Object to accelerate printing of LLVM struct MethodInfo; // Defined in ExecutionAnnotations.h class CallInst; class ReturnInst; class BranchInst; +class LoadInst; +class StoreInst; class AllocationInst; -typedef uint64_t PointerTy; - -union GenericValue { - bool BoolVal; - unsigned char UByteVal; - signed char SByteVal; - unsigned short UShortVal; - signed short ShortVal; - unsigned int UIntVal; - signed int IntVal; - uint64_t ULongVal; - int64_t LongVal; - double DoubleVal; - float FloatVal; - PointerTy PointerVal; - unsigned char Untyped[8]; -}; - // AllocaHolder - Object to track all of the blocks of memory allocated by // alloca. When the function returns, this object is poped off the execution // stack, which causes the dtor to be run, which frees all the alloca'd memory. @@ -90,25 +77,31 @@ struct ExecutionContext { // Interpreter - This class represents the entirety of the interpreter. // -class Interpreter { - Module *CurMod; // The current Module being executed (0 if none) +class Interpreter : public ExecutionEngine { int ExitCode; // The exit code to be returned by the lli util + bool Debug; // Debug mode enabled? bool Profile; // Profiling enabled? bool Trace; // Tracing enabled? int CurFrame; // The current stack frame being inspected + TargetData TD; // The runtime stack of executing code. The top of the stack is the current // function record. std::vector ECStack; public: - Interpreter(); - inline ~Interpreter() { CW.setModule(0); delete CurMod; } + Interpreter(Module *M, unsigned Config, bool DebugMode, bool TraceMode); + inline ~Interpreter() { CW.setModule(0); } // getExitCode - return the code that should be the exit code for the lli // utility. inline int getExitCode() const { return ExitCode; } - inline Module *getModule() const { return CurMod; } + + /// run - Start execution with the specified function and arguments. + /// + virtual int run(const std::string &FnName, + const std::vector &Args); + // enableProfiling() - Turn profiling on, clear stats? void enableProfiling() { Profile = true; } @@ -117,8 +110,6 @@ public: void handleUserInput(); // User Interation Methods... - void loadModule(const std::string &Filename); - bool flushModule(); bool callMethod(const std::string &Name); // return true on failure void setBreakpoint(const std::string &Name); void infoValue(const std::string &Name); @@ -128,7 +119,6 @@ public: bool callMainMethod(const std::string &MainName, const std::vector &InputFilename); - GenericValue CreateArgv(const std::vector &InputArgv); void list(); // Do the 'list' command void printStackTrace(); // Do the 'backtrace' command @@ -161,7 +151,17 @@ public: // inline bool isStopped() const { return !ECStack.empty(); } + //FIXME: private: +public: + GenericValue executeGEPOperation(Value *Ptr, User::op_iterator I, + User::op_iterator E, ExecutionContext &SF); + void executeLoadInst(LoadInst &I, ExecutionContext &SF); + void executeStoreInst(StoreInst &I, ExecutionContext &SF); + + private: // Helper functions + void *getPointerToFunction(const Function *F) { return (void*)F; } + // getCurrentExecutablePath() - Return the directory that the lli executable // lives in. // diff --git a/lib/ExecutionEngine/Interpreter/Support.cpp b/lib/ExecutionEngine/Interpreter/Support.cpp index 4c31d2692a..5f4137ce5d 100644 --- a/lib/ExecutionEngine/Interpreter/Support.cpp +++ b/lib/ExecutionEngine/Interpreter/Support.cpp @@ -7,6 +7,7 @@ #include "Interpreter.h" #include "llvm/SymbolTable.h" #include "llvm/Assembly/Writer.h" +#include "llvm/Module.h" #include using std::cout; @@ -38,7 +39,7 @@ std::vector Interpreter::LookupMatchingNames(const std::string &Name) { Function *CurMeth = getCurrentMethod(); if (CurMeth) ::LookupMatchingNames(Name, CurMeth->getSymbolTable(), Results); - if (CurMod ) ::LookupMatchingNames(Name, CurMod ->getSymbolTable(), Results); + ::LookupMatchingNames(Name, getModule().getSymbolTable(), Results); return Results; } diff --git a/lib/ExecutionEngine/Interpreter/UserInput.cpp b/lib/ExecutionEngine/Interpreter/UserInput.cpp index f0975a72d8..3d2b1de60a 100644 --- a/lib/ExecutionEngine/Interpreter/UserInput.cpp +++ b/lib/ExecutionEngine/Interpreter/UserInput.cpp @@ -7,6 +7,7 @@ #include "Interpreter.h" #include "llvm/Bytecode/Reader.h" #include "llvm/DerivedTypes.h" +#include "llvm/Function.h" #include "llvm/Transforms/Utils/Linker.h" #include using std::string; @@ -18,8 +19,8 @@ enum CommandID { Print, Info, List, StackTrace, Up, Down, // Inspection Next, Step, Run, Finish, Call, // Control flow changes Break, Watch, // Debugging - Load, Flush, - TraceOpt, ProfileOpt // Toggle features + Flush, + TraceOpt, // Toggle features }; // CommandTable - Build a lookup table for the commands available to the user... @@ -53,11 +54,9 @@ static struct CommandTableElement { { "break" , Break }, { "b", Break }, { "watch" , Watch }, - { "load" , Load }, { "flush" , Flush }, { "trace" , TraceOpt }, - { "profile" , ProfileOpt }, }; static CommandTableElement *CommandTableEnd = CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]); @@ -90,11 +89,6 @@ void Interpreter::handleUserInput() { switch (E->CID) { case Quit: UserQuit = true; break; - case Load: - cin >> Command; - loadModule(Command); - break; - case Flush: flushModule(); break; case Print: cin >> Command; print(Command); @@ -132,11 +126,6 @@ void Interpreter::handleUserInput() { cout << "Tracing " << (Trace ? "enabled\n" : "disabled\n"); break; - case ProfileOpt: - Profile = !Profile; - cout << "Profiling " << (Trace ? "enabled\n" : "disabled\n"); - break; - default: cout << "Command '" << Command << "' unimplemented!\n"; break; @@ -145,61 +134,6 @@ void Interpreter::handleUserInput() { } while (!UserQuit); } -//===----------------------------------------------------------------------===// -// loadModule - Load a new module to execute... -// -void Interpreter::loadModule(const string &Filename) { - string ErrorMsg; - if (CurMod && !flushModule()) return; // Kill current execution - - CurMod = ParseBytecodeFile(Filename, &ErrorMsg); - if (CurMod == 0) { - cout << "Error parsing '" << Filename << "': No module loaded: " - << ErrorMsg << "\n"; - return; - } - CW.setModule(CurMod); // Update Writer - -#if 0 - string RuntimeLib = getCurrentExecutablePath(); - if (!RuntimeLib.empty()) RuntimeLib += "/"; - RuntimeLib += "RuntimeLib.bc"; - - if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) { - if (LinkModules(CurMod, SupportLib, &ErrorMsg)) - std::cerr << "Error Linking runtime library into current module: " - << ErrorMsg << "\n"; - } else { - std::cerr << "Error loading runtime library '"+RuntimeLib+"': " - << ErrorMsg << "\n"; - } -#endif -} - - -//===----------------------------------------------------------------------===// -// flushModule - Return true if the current program has been unloaded. -// -bool Interpreter::flushModule() { - if (CurMod == 0) { - cout << "Error flushing: No module loaded!\n"; - return false; - } - - if (!ECStack.empty()) { - // TODO: if use is not sure, return false - cout << "Killing current execution!\n"; - ECStack.clear(); - CurFrame = -1; - } - - CW.setModule(0); - delete CurMod; - CurMod = 0; - ExitCode = 0; - return true; -} - //===----------------------------------------------------------------------===// // setBreakpoint - Enable a breakpoint at the specified location // @@ -272,7 +206,7 @@ bool Interpreter::callMainMethod(const string &Name, return true; } - Args.push_back(CreateArgv(InputArgv)); + Args.push_back(PTOGV(CreateArgv(InputArgv))); } // fallthrough case 1: diff --git a/lib/ExecutionEngine/Makefile b/lib/ExecutionEngine/Makefile index a0e73d7150..c31fb5e2da 100644 --- a/lib/ExecutionEngine/Makefile +++ b/lib/ExecutionEngine/Makefile @@ -1,6 +1,10 @@ LEVEL = ../.. TOOLNAME = lli -USEDLIBS = bcreader vmcore analysis.a support.a target.a transforms.a +PARALLEL_DIRS = Interpreter JIT + +JITLIBS = lli-jit codegen x86 scalaropts.a +USEDLIBS = lli-interpreter $(JITLIBS) bcreader vmcore analysis.a support.a target.a +#transforms.a # Have gcc tell the linker to export symbols from the program so that # dynamically loaded modules can be linked against them. diff --git a/tools/lli/Makefile b/tools/lli/Makefile index a0e73d7150..c31fb5e2da 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -1,6 +1,10 @@ LEVEL = ../.. TOOLNAME = lli -USEDLIBS = bcreader vmcore analysis.a support.a target.a transforms.a +PARALLEL_DIRS = Interpreter JIT + +JITLIBS = lli-jit codegen x86 scalaropts.a +USEDLIBS = lli-interpreter $(JITLIBS) bcreader vmcore analysis.a support.a target.a +#transforms.a # Have gcc tell the linker to export symbols from the program so that # dynamically loaded modules can be linked against them. diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 3f718e599e..be6ed11794 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -1,85 +1,101 @@ -//===----------------------------------------------------------------------===// -// LLVM INTERPRETER/DEBUGGER/PROFILER UTILITY +//===- lli.cpp - LLVM Interpreter / Dynamic compiler ----------------------===// // -// This utility is an interactive frontend to almost all other LLVM -// functionality. It may be used as an interpreter to run code, a debugger to -// find problems, or a profiler to analyze execution frequencies. +// This utility provides a way to execute LLVM bytecode without static +// compilation. This consists of a very simple and slow (but portable) +// interpreter, along with capability for system specific dynamic compilers. At +// runtime, the fastest (stable) execution engine is selected to run the +// program. This means the JIT compiler for the current platform if it's +// available. // //===----------------------------------------------------------------------===// -#include "Interpreter.h" +#include "ExecutionEngine.h" #include "Support/CommandLine.h" +#include "llvm/Bytecode/Reader.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetMachineImpls.h" -static cl::opt -InputFile(cl::desc(""), cl::Positional, cl::init("-")); - -static cl::list -InputArgv(cl::ConsumeAfter, cl::desc("...")); +namespace { + cl::opt + InputFile(cl::desc(""), cl::Positional, cl::init("-")); -static cl::opt -MainFunction ("f", cl::desc("Function to execute"), cl::init("main"), - cl::value_desc("function name")); + cl::list + InputArgv(cl::ConsumeAfter, cl::desc("...")); -static cl::opt -DebugMode("d", cl::desc("Start program in debugger")); + cl::opt + MainFunction ("f", cl::desc("Function to execute"), cl::init("main"), + cl::value_desc("function name")); -static cl::opt -TraceMode("trace", cl::desc("Enable Tracing")); + cl::opt DebugMode("d", cl::desc("Start program in debugger")); -static cl::opt -ProfileMode("profile", cl::desc("Enable Profiling [unimp]")); + cl::opt TraceMode("trace", cl::desc("Enable Tracing")); + cl::opt ForceInterpreter("force-interpreter", + cl::desc("Force interpretation: disable JIT"), + cl::init(true)); +} //===----------------------------------------------------------------------===// -// Interpreter ctor - Initialize stuff +// ExecutionEngine Class Implementation // -Interpreter::Interpreter() : ExitCode(0), Profile(ProfileMode), - Trace(TraceMode), CurFrame(-1) { - CurMod = 0; - loadModule(InputFile); - - // Initialize the "backend" - initializeExecutionEngine(); - initializeExternalMethods(); + +ExecutionEngine::~ExecutionEngine() { + delete &CurMod; } //===----------------------------------------------------------------------===// // main Driver function // int main(int argc, char** argv) { - cl::ParseCommandLineOptions(argc, argv, " llvm interpreter\n"); + cl::ParseCommandLineOptions(argc, argv, + " llvm interpreter & dynamic compiler\n"); + + // Load the bytecode... + string ErrorMsg; + Module *M = ParseBytecodeFile(InputFile, &ErrorMsg); + if (M == 0) { + cout << "Error parsing '" << InputFile << "': " + << ErrorMsg << "\n"; + exit(1); + } + +#if 0 + // Link in the runtime library for LLI... + string RuntimeLib = getCurrentExecutablePath(); + if (!RuntimeLib.empty()) RuntimeLib += "/"; + RuntimeLib += "RuntimeLib.bc"; + + if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) { + if (LinkModules(M, SupportLib, &ErrorMsg)) + std::cerr << "Error Linking runtime library into current module: " + << ErrorMsg << "\n"; + } else { + std::cerr << "Error loading runtime library '"+RuntimeLib+"': " + << ErrorMsg << "\n"; + } +#endif + + // FIXME: This should look at the PointerSize and endianness of the bytecode + // file to determine the endianness and pointer size of target machine to use. + unsigned Config = TM::PtrSize64 | TM::BigEndian; + + ExecutionEngine *EE = 0; + + // If there is nothing that is forcing us to use the interpreter, make a JIT. + if (!ForceInterpreter && !DebugMode && !TraceMode) + EE = ExecutionEngine::createJIT(M, Config); + + // If we can't make a JIT, make an interpreter instead. + if (EE == 0) + EE = ExecutionEngine::createInterpreter(M, Config, DebugMode, TraceMode); // Add the module name to the start of the argv vector... - // InputArgv.insert(InputArgv.begin(), InputFile); - // Create the interpreter... - Interpreter I; - - // Handle alternate names of the program. If started as llp, enable profiling - // if started as ldb, enable debugging... - // - if (argv[0] == "ldb") // TODO: Obviously incorrect, but you get the idea - DebugMode = true; - else if (argv[0] == "llp") - ProfileMode = true; - - // If running with the profiler, enable it now... - if (ProfileMode) I.enableProfiling(); - if (TraceMode) I.enableTracing(); - - // Start interpreter into the main function... - // - if (!I.callMainMethod(MainFunction, InputArgv) && !DebugMode) { - // If not in debug mode and if the call succeeded, run the code now... - I.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 (DebugMode || I.isStopped()) - I.handleUserInput(); + // Run the main function! + int ExitCode = EE->run(MainFunction, InputArgv); - // Return the status code of the program executed... - return I.getExitCode(); + // Now that we are done executing the program, shut down the execution engine + delete EE; + return ExitCode; } -- cgit v1.2.3