From 2e42d3a3060ff0c3d4c419f17493bc6a7683e9d0 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 15 Oct 2001 05:51:48 +0000 Subject: [PATCH] Implement global variables. Struct and Pointer initializers are not implemented yet though git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@818 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ExecutionEngine/Interpreter/Execution.cpp | 163 +++++++++++++++--- .../Interpreter/ExecutionAnnotations.h | 47 +++-- .../Interpreter/ExternalFunctions.cpp | 30 +++- lib/ExecutionEngine/Interpreter/Interpreter.h | 5 +- lib/ExecutionEngine/Interpreter/UserInput.cpp | 45 ++++- tools/lli/lli.cpp | 7 +- 6 files changed, 254 insertions(+), 43 deletions(-) diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index 34a80fedd41..668ef6d713c 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -14,6 +14,109 @@ #include "llvm/Assembly/Writer.h" #include "llvm/Support/DataTypes.h" #include "llvm/Target/TargetData.h" +#include "llvm/GlobalVariable.h" + +// Create a TargetData structure to handle memory addressing and size/alignment +// computations +// +static TargetData TD("lli Interpreter"); + +//===----------------------------------------------------------------------===// +// Annotation Wrangling code +//===----------------------------------------------------------------------===// + +void Interpreter::initializeExecutionEngine() { + AnnotationManager::registerAnnotationFactory(MethodInfoAID, + &MethodInfo::Create); + AnnotationManager::registerAnnotationFactory(GlobalAddressAID, + &GlobalAddress::Create); +} + +// InitializeMemory - Recursive function to apply a ConstPool value into the +// specified memory location... +// +static void InitializeMemory(ConstPoolVal *Init, char *Addr) { +#define INITIALIZE_MEMORY(TYID, CLASS, TY) \ + case Type::TYID##TyID: { \ + TY Tmp = cast(Init)->getValue(); \ + memcpy(Addr, &Tmp, sizeof(TY)); \ + } return + + switch (Init->getType()->getPrimitiveID()) { + INITIALIZE_MEMORY(Bool , ConstPoolBool, bool); + INITIALIZE_MEMORY(UByte , ConstPoolUInt, unsigned char); + INITIALIZE_MEMORY(SByte , ConstPoolSInt, signed char); + INITIALIZE_MEMORY(UShort , ConstPoolUInt, unsigned short); + INITIALIZE_MEMORY(Short , ConstPoolSInt, signed short); + INITIALIZE_MEMORY(UInt , ConstPoolUInt, unsigned int); + INITIALIZE_MEMORY(Int , ConstPoolSInt, signed int); + INITIALIZE_MEMORY(ULong , ConstPoolUInt, uint64_t); + INITIALIZE_MEMORY(Long , ConstPoolSInt, int64_t); + INITIALIZE_MEMORY(Float , ConstPoolFP , float); + INITIALIZE_MEMORY(Double , ConstPoolFP , double); +#undef INITIALIZE_MEMORY + case Type::ArrayTyID: { + ConstPoolArray *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; + } + // TODO: Struct and Pointer! + case Type::StructTyID: + case Type::PointerTyID: + default: + cout << "Bad Type: " << Init->getType()->getDescription() << endl; + 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 method is just a pointer to method 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 method 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()->getValueType(); // Type to be allocated + unsigned NumElements = 1; + + if (isa(Ty) && cast(Ty)->isUnsized()) { + assert(GV->hasInitializer() && "Const val must have an initializer!"); + // Allocating a unsized array type? + Ty = cast(Ty)->getElementType(); // Get the actual type... + + // Get the number of elements being allocated by the array... + NumElements =cast(GV->getInitializer())->getValues().size(); + } + + // Allocate enough memory to hold the type... + void *Addr = malloc(NumElements * 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 +} + +//===----------------------------------------------------------------------===// +// Value Manipulation code +//===----------------------------------------------------------------------===// static unsigned getOperandSlot(Value *V) { SlotNumber *SN = (SlotNumber*)V->getAnnotation(SlotNumberAID); @@ -22,7 +125,7 @@ static unsigned getOperandSlot(Value *V) { } #define GET_CONST_VAL(TY, CLASS) \ - case Type::TY##TyID: Result.TY##Val = ((CLASS*)CPV)->getValue(); break + case Type::TY##TyID: Result.TY##Val = cast(CPV)->getValue(); break static GenericValue getOperandValue(Value *V, ExecutionContext &SF) { if (ConstPoolVal *CPV = dyn_cast(V)) { @@ -37,10 +140,26 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) { GET_CONST_VAL(Int , ConstPoolSInt); GET_CONST_VAL(Float , ConstPoolFP); GET_CONST_VAL(Double , ConstPoolFP); + case Type::PointerTyID: + if (isa(CPV)) { + Result.PointerVal = 0; + } else if (ConstPoolPointerReference *CPR = + dyn_cast(CPV)) { + assert(0 && "Not implemented!"); + } else { + assert(0 && "Unknown constant pointer type!"); + } + break; default: cout << "ERROR: Constant unimp for type: " << CPV->getType() << endl; } return Result; + } else if (GlobalValue *GV = dyn_cast(V)) { + GlobalAddress *Address = + (GlobalAddress*)GV->getOrCreateAnnotation(GlobalAddressAID); + GenericValue Result; + Result.PointerVal = (GenericValue*)Address->Ptr; + return Result; } else { unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value return SF.Values[TyP][getOperandSlot(V)]; @@ -48,7 +167,11 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) { } static void printOperandInfo(Value *V, ExecutionContext &SF) { - if (!isa(V)) { + if (isa(V)) { + cout << "Constant Pool Value\n"; + } else if (isa(V)) { + cout << "Global Value\n"; + } else { unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value unsigned Slot = getOperandSlot(V); cout << "Value=" << (void*)V << " TypeID=" << TyP << " Slot=" << Slot @@ -294,7 +417,7 @@ void Interpreter::executeRetInst(ReturnInst *I, ExecutionContext &SF) { if (RetTy) { // Nonvoid return type? cout << "Method " << M->getType() << " \"" << M->getName() << "\" returned "; - printValue(RetTy, Result); + print(RetTy, Result); cout << endl; if (RetTy->isIntegral()) @@ -319,7 +442,7 @@ void Interpreter::executeRetInst(ReturnInst *I, ExecutionContext &SF) { // instruction. cout << "Method " << M->getType() << " \"" << M->getName() << "\" returned "; - printValue(RetTy, Result); + print(RetTy, Result); cout << endl; } } @@ -341,11 +464,6 @@ void Interpreter::executeBrInst(BranchInst *I, ExecutionContext &SF) { // Memory Instruction Implementations //===----------------------------------------------------------------------===// -// Create a TargetData structure to handle memory addressing and size/alignment -// computations -// -static TargetData TD("lli Interpreter"); - void Interpreter::executeAllocInst(AllocationInst *I, ExecutionContext &SF) { const Type *Ty = I->getType()->getValueType(); // Type to be allocated unsigned NumElements = 1; @@ -367,7 +485,7 @@ void Interpreter::executeAllocInst(AllocationInst *I, ExecutionContext &SF) { SetValue(I, Result, SF); if (I->getOpcode() == Instruction::Alloca) { - // Keep track to free it later... + // TODO: FIXME: alloca should keep track of memory to free it later... } } @@ -602,10 +720,6 @@ unsigned MethodInfo::getValueSlot(const Value *V) { } -void Interpreter::initializeExecutionEngine() { - AnnotationManager::registerAnnotationFactory(MethodInfoAID, CreateMethodInfo); -} - //===----------------------------------------------------------------------===// // callMethod - Execute the specified method... // @@ -703,9 +817,6 @@ void Interpreter::stepInstruction() { // Do the 'step' command } // --- UI Stuff... - - - void Interpreter::nextInstruction() { // Do the 'next' command if (ECStack.empty()) { cout << "Error: no program running, cannot 'next'!\n"; @@ -746,7 +857,6 @@ void Interpreter::run() { if (HitBreakpoint) { cout << "Breakpoint hit!\n"; } - // Print the next instruction to execute... printCurrentInstruction(); } @@ -787,8 +897,6 @@ void Interpreter::printCurrentInstruction() { } void Interpreter::printValue(const Type *Ty, GenericValue V) { - cout << Ty << " "; - switch (Ty->getPrimitiveID()) { case Type::BoolTyID: cout << (V.BoolVal?"true":"false"); break; case Type::SByteTyID: cout << V.SByteVal; break; @@ -806,15 +914,20 @@ void Interpreter::printValue(const Type *Ty, GenericValue V) { } } -void Interpreter::printValue(const string &Name) { +void Interpreter::print(const Type *Ty, GenericValue V) { + cout << Ty << " "; + printValue(Ty, V); +} + +void Interpreter::print(const string &Name) { Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name)); if (!PickedVal) return; if (const Method *M = dyn_cast(PickedVal)) { cout << M; // Print the method } else { // Otherwise there should be an annotation for the slot# - printValue(PickedVal->getType(), - getOperandValue(PickedVal, ECStack[CurFrame])); + print(PickedVal->getType(), + getOperandValue(PickedVal, ECStack[CurFrame])); cout << endl; } @@ -825,8 +938,8 @@ void Interpreter::infoValue(const string &Name) { if (!PickedVal) return; cout << "Value: "; - printValue(PickedVal->getType(), - getOperandValue(PickedVal, ECStack[CurFrame])); + print(PickedVal->getType(), + getOperandValue(PickedVal, ECStack[CurFrame])); cout << endl; printOperandInfo(PickedVal, ECStack[CurFrame]); } diff --git a/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h b/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h index bdcffd800c5..f6a27265f04 100644 --- a/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h +++ b/lib/ExecutionEngine/Interpreter/ExecutionAnnotations.h @@ -25,20 +25,19 @@ struct MethodInfo : public Annotation { MethodInfo(Method *M); vector NumPlaneElements; + + // Create - Factory function to allow MethodInfo annotations to be + // created on demand. + // + static Annotation *Create(AnnotationID AID, const Annotable *O, void *) { + assert(AID == MethodInfoAID); + return new MethodInfo(cast((Value*)O)); // Simply invoke the ctor + } + private: unsigned getValueSlot(const Value *V); }; -// CreateMethodInfo - Factory function to allow MethodInfo annotations to be -// created on demand. -// -inline static Annotation *CreateMethodInfo(AnnotationID AID, const Annotable *O, - void *) { - assert(AID == MethodInfoAID); - return new MethodInfo((Method*)O); // Simply invoke the ctor -} - - //===----------------------------------------------------------------------===// // Support for the SlotNumber annotation //===----------------------------------------------------------------------===// @@ -89,4 +88,32 @@ static AnnotationID BreakpointAID( AnnotationManager::getID("Interpreter::Breakpoint")); // 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 Method's, +// this pointer is the Method 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 4c2039ded4c..7be3336c586 100644 --- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp +++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp @@ -91,10 +91,32 @@ void Interpreter::callExternalMethod(Method *M, // extern "C" { // Don't add C++ manglings to llvm mangling :) +// Implement void printstr([ubyte {x N}] *) +GenericValue lle_VP_printstr(MethodType *M, const vector &ArgVal){ + assert(ArgVal.size() == 1 && "printstr only takes one argument!"); + cout << (char*)ArgVal[0].PointerVal; + return GenericValue(); +} + // Implement 'void print(X)' for every type... GenericValue lle_X_print(MethodType *M, const vector &ArgVals) { assert(ArgVals.size() == 1 && "generic print only takes one argument!"); - Interpreter::printValue(M->getParamTypes()[0], ArgVals[0]); + + Interpreter::print(M->getParamTypes()[0], ArgVals[0]); + return GenericValue(); +} + +// Implement 'void printVal(X)' for every type... +GenericValue lle_X_printVal(MethodType *M, const vector &ArgVal) { + assert(ArgVal.size() == 1 && "generic print only takes one argument!"); + + // Specialize print([ubyte {x N} ] *) + if (PointerType *PTy = dyn_cast(M->getParamTypes()[0].get())) + if (const ArrayType *ATy = dyn_cast(PTy->getValueType())) { + return lle_VP_printstr(M, ArgVal); + } + + Interpreter::printValue(M->getParamTypes()[0], ArgVal[0]); return GenericValue(); } @@ -104,4 +126,10 @@ GenericValue lle_Vb_putchar(MethodType *M, const vector &Args) { return GenericValue(); } +// void "putchar"(ubyte) +GenericValue lle_VB_putchar(MethodType *M, const vector &Args) { + cout << Args[0].UByteVal; + return GenericValue(); +} + } // End extern "C" diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index e7f5c864a61..4b73b3d28b0 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -74,10 +74,13 @@ public: void handleUserInput(); // User Interation Methods... + void loadModule(const string &Filename); + bool flushModule(); bool callMethod(const string &Name); // return true on failure void setBreakpoint(const string &Name); void infoValue(const string &Name); - void printValue(const string &Name); + void print(const string &Name); + static void print(const Type *Ty, GenericValue V); static void printValue(const Type *Ty, GenericValue V); diff --git a/lib/ExecutionEngine/Interpreter/UserInput.cpp b/lib/ExecutionEngine/Interpreter/UserInput.cpp index e9fc9db3436..4c2faf6ca16 100644 --- a/lib/ExecutionEngine/Interpreter/UserInput.cpp +++ b/lib/ExecutionEngine/Interpreter/UserInput.cpp @@ -5,6 +5,7 @@ //===----------------------------------------------------------------------===// #include "Interpreter.h" +#include "llvm/Bytecode/Reader.h" #include "llvm/Assembly/Writer.h" #include @@ -81,9 +82,14 @@ 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; - printValue(Command); + print(Command); break; case Info: cin >> Command; @@ -118,6 +124,43 @@ void Interpreter::handleUserInput() { } while (!UserQuit); } +//===----------------------------------------------------------------------===// +// loadModule - Load a new module to execute... +// +void Interpreter::loadModule(const string &Filename) { + if (CurMod && !flushModule()) return; // Kill current execution + + CurMod = ParseBytecodeFile(Filename); + if (CurMod == 0) { + cout << "Error parsing '" << Filename << "': No module loaded.\n"; + return; + } + + // TODO: link in support library... +} + + +//===----------------------------------------------------------------------===// +// 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; + } + + delete CurMod; + CurMod = 0; + ExitCode = 0; + return true; +} //===----------------------------------------------------------------------===// // setBreakpoint - Enable a breakpoint at the specified location diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 9611e0ca85f..9bb514e54e7 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -9,7 +9,6 @@ #include "Interpreter.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Bytecode/Reader.h" cl::String InputFilename("" , "Input filename", cl::NoFlags, "-"); cl::String MainFunction ("f" , "Function to execute", cl::NoFlags, "main"); @@ -21,10 +20,8 @@ cl::Flag ProfileMode ("profile", "Enable Profiling [unimp]"); // Interpreter ctor - Initialize stuff // Interpreter::Interpreter() : ExitCode(0), Profile(ProfileMode), CurFrame(-1) { - CurMod = ParseBytecodeFile(InputFilename); - if (CurMod == 0) { - cout << "Error parsing '" << InputFilename << "': No module loaded.\n"; - } + CurMod = 0; + loadModule(InputFilename); // Initialize the "backend" initializeExecutionEngine();